线程安全唯一编号生成器

时间:2019-03-24 19:20:45

标签: java multithreading thread-safety

如何实现唯一数字的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);
}

谢谢。

2 个答案:

答案 0 :(得分:2)

这里有两个问题,安全发布,然后是变量(shuffle())的后续线程安全,然后是读取(get(0))。

我认为您的代码根本不涉及安全发布。为此,请使用volatilefinal,对于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);