Is there something wrong with the thread safety of this java code? Topics 1-10 add numbers through sample.add () and Threads 11-20 call removeAndDouble () and print the results to stdout. I remember that someone said that assigning an object in the same way as mine in removeAndDouble (), using it outside the synchronized block, can be an unsafe thread. That the compiler can optimize instructions so that they come from a sequence. Is this the case here? Is the removeAndDouble () method unsafe?
Is there anything else in terms of concurrency with this code? I am trying to better understand concurrency and the memory model with java (1.6 up).
import java.util.*; import java.util.concurrent.*; public class Sample { private final List<Integer> list = new ArrayList<Integer>(); public void add(Integer o) { synchronized (list) { list.add(o); list.notify(); } } public void waitUntilEmpty() { synchronized (list) { while (!list.isEmpty()) { try { list.wait(10000); } catch (InterruptedException ex) { } } } } public void waitUntilNotEmpty() { synchronized (list) { while (list.isEmpty()) { try { list.wait(10000); } catch (InterruptedException ex) { } } } } public Integer removeAndDouble() { // item declared outside synchronized block Integer item; synchronized (list) { waitUntilNotEmpty(); item = list.remove(0); } // Would this ever be anything but that from list.remove(0)? return Integer.valueOf(item.intValue() * 2); } public static void main(String[] args) { final Sample sample = new Sample(); for (int i = 0; i < 10; i++) { Thread t = new Thread() { public void run() { while (true) { System.out.println(getName()+" Found: " + sample.removeAndDouble()); } } }; t.setName("Consumer-"+i); t.setDaemon(true); t.start(); } final ExecutorService producers = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { final int j = i * 10000; Thread t = new Thread() { public void run() { for (int c = 0; c < 1000; c++) { sample.add(j + c); } } }; t.setName("Producer-"+i); t.setDaemon(false); producers.execute(t); } producers.shutdown(); try { producers.awaitTermination(600, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } sample.waitUntilEmpty(); System.out.println("Done."); } }
- .
.
-, waitUntilEmpty , list.notifyAll() list.remove(0) removeAndDouble. 10 wait(10000).
waitUntilEmpty
list.notifyAll()
list.remove(0)
removeAndDouble
wait(10000)
-, list.notify add(Integer) notifyAll, notify , , waitUntilEmpty waitUntilNotEmpty.
list.notify
add(Integer)
notifyAll
notify
waitUntilNotEmpty
-, , , , (waitUntilEmpty), no-arg .
. .
, list, . . , list item, item .
list
item
list , ( .)
as-is . - .
- . , .
. , , . . . - Integer item. , .
Integer item
, ( ). , , .
, , java.util.concurrent BlockingQueue () . , .
java.util.concurrent
BlockingQueue