class ABC{
private static Random random = new Random();
private static AtomicLong uniqueLongId = new AtomicLong(System.currentTimeMillis());
public static long getUniqueLongId(){
long id = uniqueLongId.incrementAndGet();
long uniqueID = Math.abs(random.nextLong()) + id;
return uniqueID;
//the above code we can write in one line
//return Math.abs(random.nextLong())+uniqueLongId.incrementAndGet();
}
}
以上方法getUniqueLongId()是否会在多线程环境中为我提供唯一ID。我关注的是:知道uniqueLongId是原子的并且假设调用incrementAndGet()将是一个线程安全的调用,但代码的另一部分不同步。这不意味着方法getUniqueLongId()本身不是线程安全的吗?因此可能无法返回唯一ID?
请解释..
答案 0 :(得分:2)
Java 7 docs写道:
java.util.Random
的实例是线程安全的。但是,跨线程同时使用相同的java.util.Random
实例可能会遇到争用并因此导致性能不佳。请考虑在多线程设计中使用ThreadLocalRandom
。
因此,您的代码在Java 7中是线程安全的。每个操作都是对线程安全方法的调用,或者仅对局部变量进行操作。并且您不需要原子性,即您不需要将下一个序列号与下一个随机数配对。
As(根据您的评论)在旧版本的API文档中没有这样的保证,理论上实现可能是非线程安全的。但是,查看Sun JDK 1.4.2.19中的src.zip
(这是我最老的版本),该代码已经使用了原子变量,从而在实践中提供了线程安全的行为。
也就是说,您的代码还存在许多其他问题。如上所述,表现可能不好。作为assylias already wrote in a comment,此方法不会为您提供比简单Random
更多的唯一数字。此外,Math.abs(Long.MIN_VALUE)
仍然是负数,正的随机数加上一个id可能会导致溢出和环绕。因此,如果您需要正数,则必须增加更多关注。最后uniqueID &= 0x7fffffffffffffffL
可能比Math.abs
更合适。
答案 1 :(得分:1)