Потокобезопасный генератор уникальных чисел - PullRequest
0 голосов
/ 24 марта 2019

Как реализовать 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 ]

2 голосов
/ 24 марта 2019

Здесь есть две проблемы: безопасная публикация, а затем последующая безопасность потока для mutate (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);
}

См. Брайан Гетц Параллелизм Java на практике для получения дополнительной информации, особенно Безопасная публикация. SO также кратко обсуждает шаблон безопасной публикации .

Получение уникальных чисел - это просто логика, не связанная с безопасностью потоков. Сначала перемешайте только один раз в ctor, затем просто увеличьте счетчик, чтобы вернуть числа по порядку. Помните, что в вашем списке только 1000 номеров, поэтому вы можете вернуть не более 1000 уникальных номеров.

private int index;
public synchronized Integer generate() {
    if( index >= 1000 ) throw IllegalArgumentError();
    return list.get( index++ );
}
0 голосов
/ 24 марта 2019

Я предполагаю здесь (извините, если не в базе), что вы ищете случайное число в диапазоне от 0 <= x <1000: </p>

ThreadLocalRandom.current().nextInt(1000);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...