如何实现唯一数字的Java线程安全生成器? 这是我的版本
public class Generator {
List<Integer> list = new ArrayList<>();
public Generator() {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
}
public Integer generate() {
Collections.shuffle(list);
return list.get(0);
}
}
但是从理论上讲,洗牌时可以获得唯一的数字。如何实现独特性?随机播放时,我是否需要在我的收藏集之间进行同步?
synchronized (list) {
Collections.shuffle(list);
}
谢谢。
答案 0 :(得分:2)
这里有两个问题,安全发布,然后是变量(shuffle()
)的后续线程安全,然后是读取(get(0)
)。
我认为您的代码根本不涉及安全发布。为此,请使用volatile
或final
,对于volatile
,请在ctor中最后执行分配。
public class Generator {
private final List<Integer> list = new ArrayList<>();
public Generator() {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
}
或
public class Generator {
private volatile List<Integer> list;
public Generator() {
List<Integer> temp = = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
temp.add(i);
}
list = temp;
}
现在,我认为您可以在list
(或任何其他对象)上进行同步以获得线程安全。您必须确保get
在同步块内。请注意,您的代码存在错误,实际上并不会产生唯一的数字。
public Integer generate() {
synchronized( list ) {
Collections.shuffle(list);
return list.get(0);
}
}
或
public synchronized Integer generate() {
Collections.shuffle(list);
return list.get(0);
}
有关更多信息,请参见Brian Goetz Java并发实践。安全发布。 SO也有一个简短的discussion of the Safe Publication pattern。
获取唯一编号只是逻辑,与线程安全无关。首先在ctor中只洗一次,然后只增加一个计数器以按顺序返回数字。请记住,列表中只有1000个数字,因此您最多可以返回1000个唯一数字。
private int index;
public synchronized Integer generate() {
if( index >= 1000 ) throw IllegalArgumentError();
return list.get( index++ );
}
答案 1 :(得分:0)
我在这里(很抱歉,如果偏离基准),您正在寻找0 <= x <1000之间的随机数:
ThreadLocalRandom.current().nextInt(1000);