A synchronized block is a Java construct that acquires an object's monitor while executing guarded code. The monitor permits only one thread at a time to enter that block, protecting shared resources from simultaneous changes and race conditions. section 5.2.2 section 7.1
Use the same monitor around related producer and consumer operations. A thread entering the block makes the other wait until the block finishes, while instructions outside the block can still run concurrently. This protection can prevent failures, but excessive waiting can reduce performance. section 5.2.2 section 7.4
Protecting a shared list
Producer and Consumer threads both synchronize on Main.list. The consumer checks whether the list contains values, reads the first value, and removes it; the producer checks capacity, generates a value, and adds it. With both operations guarded by the list monitor, only one thread changes the list at a time. VisualVM shows lower CPU use and thread execution interrupted by the monitor. Using two nested blocks with listA and listB in opposite orders instead allows a deadlock: each thread holds one monitor while waiting for the other. section 7.1 section 8.1
Listing 7.2 The consumer thread’s definition
public class Consumer extends Thread {
private Logger log = Logger.getLogger(Consumer.class.getName());
public Consumer(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 1_000_000; i++) { #1
synchronized (Main.list) { #2
if (Main.list.size() > 0) { #3
int x = Main.list.get(0); #4
Main.list.remove(0); #4
log.info("Consumer " + #5
Thread.currentThread().getName() +
" removed value " + x);
}
}
}
}
}
Inspect the consumer implementation to see the shared-list check, read, and removal enclosed by one synchronized block. section 7.1
