有关此主题的SO上有几篇帖子.每个人都谈到一个特定的方法,所以想在一个问题中进行比较.
使用新的Date()作为唯一标识符
在Java中生成全局唯一标识符
我正在尝试实现一个功能,我们可以在日志文件中识别某些事件.这些事件需要与唯一ID相关联.我正在尝试为这个独特的ID生成策略.ID必须包含两部分:一些静态信息+一些动态信息当需要调试事件时,可以搜索日志.我有三种方式:
静态信息+ Joda日期时间("abc"+ 2014-01-30T12:36:12.703)
静态信息+原子整数
静态信息+ UUID
对于此问题的范围,不考虑多个JVM.我需要在一个JVM上以有效的方式生成唯一ID.此外,我将无法使用数据库相关的解决方案.
上述3种策略中哪一种效果最好?
如果没有上述任何一种策略?
Joda基于时间的战略是否健全?JVM是单一的,但会有并发用户,因此可以有并发事件.
结合上述/其他策略之一,我是否需要使我的方法线程安全/同步?
Basil Bourqu.. 10
我有与您相同的需求,区分与日志中其他不相关条目交错的相关条目的线程.我已经尝试了所有三种建议的方法.我的经验是4D而不是Java,但类似.
约会时间就我而言,我使用的日期时间值已经解析为整秒.这只是一个太大的粒度.我很容易发生在同一秒内开始多个事件的碰撞.该死的那些快速的电脑!
在您使用捆绑的java.util.Date或Joda-Time(强烈建议用于其他目的)的情况下,两者都解析为毫秒.在现代计算机中,毫秒是很长的一段时间,所以我不建议这样做.
在Java 8中,新的java.time.*包(受Joda-Time启发,由JSR 310定义)解析为纳秒.这似乎是一个更好的标识符,但没有.首先,您的计算机的物理计时时钟可能不支持如此精细的分辨率.另一个是计算机越来越快.最后,计算机的时钟可以重置,实际上它是复位经常计算机时钟漂移颇有几分.现代操作系统通过在本地或通过互联网频繁检查时间服务器来重置其时钟.
此外,日志已经有时间戳,因此使用日期时间作为我们的标识符,我们无法获得任何额外的好处.实际上,在日志条目中有第二个日期时间实际上可能会引起混淆.
序列号通过"原子整数",我假设你的意思是一个序列号递增到数字增加.
这对你的目的来说似乎有些过分.
您不关心序列,它对于分组日志条目没有意义.如果一个组在另一个组之前或之后出现第n个数字,您并不在意.
维持序列是一种痛苦,一种潜在的失败点.我总是最终遇到维护序列的管理问题.
因此,这种方法在不增加任何特殊益处的情
UUID答对了!正是你需要的.
甲UUID容易产生,使用,以生成版本3点或4任一的UUID捆绑java.util.UUID中类的能力,或使用第三方库,或访问命令行的uuidgen
工具.
对于非常高的音量,[版本1] UUID(MAC +日期时间+随机数)将是最佳的.对于日志记录,版本4 UUID(完全随机)是绝对可以接受的.
碰撞不是一个现实的问题.特别是对于您将为日志生成的有限数量的值.我很惊讶那些不理解数字的人,他们说永远不会用UUID替换序列.然而,当被按下时,我所知道的每个程序员和系统管理员都经历过至少一个序列的失败.
不关心线程安全性.不关心争用(参见我对我的另一个答案的测试结果).
UUID的另一个好处是它通常的十六进制表示,例如:
6536ca53-BCAD-4552-977f-16945fee13e2
......很容易识别.识别后,读者立即知道字符串是唯一的标识符.因此,它在您的日志中的存在是自我记录的.
我发现UUID是计算机的Duct磁带.我一直在寻找它们的新用途.
因此,在相关代码的开头,生成一个UUID,然后将其嵌入到每个相关的日志条目中.
虽然UUID的十六进制字符串表示难以读写,但实际上您只需扫描开头或结尾的几个数字.或者在我们的现代控制台工具中使用带有搜索和过滤功能的复制粘贴.
UUID在Microsoft世界中称为GUID.
UUID 不是字符串,而是128位值.位,只是内存中的位,"开"/"关"值.某些数据库(如Postgres)知道如何处理和存储UUID作为128位值.如果我们希望向人类显示这些位,我们可以使用一系列128位"1"和"0".但是人类在尝试读取或写入128位的1和0时表现不佳.所以我们使用十六进制表示.但即使32个十六进制数字对于人类也是如此,所以我们将字符串分成用连字符分隔的组,如上所示,总共36个字符.
UUID的规范非常明确,十六进制表示应该是小写的.规范说,当从字符串输入创建UUID时,应该容忍大写.但是在生成十六进制字符串时,它应该是小写的.许多UUID实现都忽略了这一要求.我建议坚持使用规范并将您的UUID十六进制字符串转换为小写.
MDC - 映射的诊断上下文
我还没有使用过MDC,但想指出来......
一些日志记录框架正在添加对标记相关日志条目的想法的支持.这种支持称为映射诊断上下文(MDC).MDC基于每个线程管理上下文信息.
一篇快速入门的文章是Log4j MDC(映射诊断上下文):什么和为什么.
最好的伐木外观SLF4J提供了这样的MDC功能.Logback的最佳实现Logback有一章记录了它的MDC功能.
计算机很快,使用时间尝试创建一个独特的值将会失败.
而是使用UUID.从JSE 6.0 UUID API页面 " [UUID is]一个表示不可变的通用唯一标识符(UUID)的类. "
这是一些代码:
import java.util.UUID; private String id; id = UUID.randomUUID().toString();
我有与您相同的需求,区分与日志中其他不相关条目交错的相关条目的线程.我已经尝试了所有三种建议的方法.我的经验是4D而不是Java,但类似.
就我而言,我使用的日期时间值已经解析为整秒.这只是一个太大的粒度.我很容易发生在同一秒内开始多个事件的碰撞.该死的那些快速的电脑!
在您使用捆绑的java.util.Date或Joda-Time(强烈建议用于其他目的)的情况下,两者都解析为毫秒.在现代计算机中,毫秒是很长的一段时间,所以我不建议这样做.
在Java 8中,新的java.time.*包(受Joda-Time启发,由JSR 310定义)解析为纳秒.这似乎是一个更好的标识符,但没有.首先,您的计算机的物理计时时钟可能不支持如此精细的分辨率.另一个是计算机越来越快.最后,计算机的时钟可以重置,实际上它是复位经常计算机时钟漂移颇有几分.现代操作系统通过在本地或通过互联网频繁检查时间服务器来重置其时钟.
此外,日志已经有时间戳,因此使用日期时间作为我们的标识符,我们无法获得任何额外的好处.实际上,在日志条目中有第二个日期时间实际上可能会引起混淆.
通过"原子整数",我假设你的意思是一个序列号递增到数字增加.
这对你的目的来说似乎有些过分.
您不关心序列,它对于分组日志条目没有意义.如果一个组在另一个组之前或之后出现第n个数字,您并不在意.
维持序列是一种痛苦,一种潜在的失败点.我总是最终遇到维护序列的管理问题.
因此,这种方法在不增加任何特殊益处的情
答对了!正是你需要的.
甲UUID容易产生,使用,以生成版本3点或4任一的UUID捆绑java.util.UUID中类的能力,或使用第三方库,或访问命令行的uuidgen
工具.
对于非常高的音量,[版本1] UUID(MAC +日期时间+随机数)将是最佳的.对于日志记录,版本4 UUID(完全随机)是绝对可以接受的.
碰撞不是一个现实的问题.特别是对于您将为日志生成的有限数量的值.我很惊讶那些不理解数字的人,他们说永远不会用UUID替换序列.然而,当被按下时,我所知道的每个程序员和系统管理员都经历过至少一个序列的失败.
不关心线程安全性.不关心争用(参见我对我的另一个答案的测试结果).
UUID的另一个好处是它通常的十六进制表示,例如:
6536ca53-BCAD-4552-977f-16945fee13e2
......很容易识别.识别后,读者立即知道字符串是唯一的标识符.因此,它在您的日志中的存在是自我记录的.
我发现UUID是计算机的Duct磁带.我一直在寻找它们的新用途.
因此,在相关代码的开头,生成一个UUID,然后将其嵌入到每个相关的日志条目中.
虽然UUID的十六进制字符串表示难以读写,但实际上您只需扫描开头或结尾的几个数字.或者在我们的现代控制台工具中使用带有搜索和过滤功能的复制粘贴.
UUID在Microsoft世界中称为GUID.
UUID 不是字符串,而是128位值.位,只是内存中的位,"开"/"关"值.某些数据库(如Postgres)知道如何处理和存储UUID作为128位值.如果我们希望向人类显示这些位,我们可以使用一系列128位"1"和"0".但是人类在尝试读取或写入128位的1和0时表现不佳.所以我们使用十六进制表示.但即使32个十六进制数字对于人类也是如此,所以我们将字符串分成用连字符分隔的组,如上所示,总共36个字符.
UUID的规范非常明确,十六进制表示应该是小写的.规范说,当从字符串输入创建UUID时,应该容忍大写.但是在生成十六进制字符串时,它应该是小写的.许多UUID实现都忽略了这一要求.我建议坚持使用规范并将您的UUID十六进制字符串转换为小写.
我还没有使用过MDC,但想指出来......
一些日志记录框架正在添加对标记相关日志条目的想法的支持.这种支持称为映射诊断上下文(MDC).MDC基于每个线程管理上下文信息.
一篇快速入门的文章是Log4j MDC(映射诊断上下文):什么和为什么.
最好的伐木外观SLF4J提供了这样的MDC功能.Logback的最佳实现Logback有一章记录了它的MDC功能.