There's two issues here, Safe Publication and then the subsequent thread safety of the mutate (shuffle()
) followed by a read (get(0)
).
I don't think your code address safe publication at all. Use volatile
or final
for that, and for volatile
do the assignment last in the ctor.
public class Generator {
private final List<Integer> list = new ArrayList<>();
public Generator() {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
}
Or
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;
}
Now I think you can synchronize on list
(or any other object) to get thread safety. You have to make sure the get
is inside the synchronized block. Note that your code has a bug and doesn't actually produce unique numbers.
public Integer generate() {
synchronized( list ) {
Collections.shuffle(list);
return list.get(0);
}
}
Or
public synchronized Integer generate() {
Collections.shuffle(list);
return list.get(0);
}
See Brian Goetz Java Concurrency in Practice for more, esp. Safe Publication. SO has a short discussion of the Safe Publication pattern too.
Getting unique numbers is just logic, not related to thread safety. First shuffle only once in the ctor, then just increment a counter to return numbers in order. Remember your list only has 1000 numbers so you can return at most 1000 unique numbers.
private int index;
public synchronized Integer generate() {
if( index >= 1000 ) throw IllegalArgumentError();
return list.get( index++ );
}