for learning purpose i have tried to implements a queue data-structure + Consumer/producer chain that is thread-safe, for learning purpose too i have not used notify/wait mechanism :
SyncQueue :
package syncpc; /** * Created by Administrator on 01/07/2009. */ public class SyncQueue { private int val = 0; private boolean set = false; boolean isSet() { return set; } synchronized public void enqueue(int val) { this.val = val; set = true; } synchronized public int dequeue() { set = false; return val; } } Consumer :
package syncpc; /** * Created by Administrator on 01/07/2009. */ public class Consumer implements Runnable { SyncQueue queue; public Consumer(SyncQueue queue, String name) { this.queue = queue; new Thread(this, name).start(); } public void run() { while(true) { if(queue.isSet()) { System.out.println(queue.dequeue()); } } } } Producer :
package syncpc; import java.util.Random; /** * Created by Administrator on 01/07/2009. */ public class Producer implements Runnable { SyncQueue queue; public Producer(SyncQueue queue, String name) { this.queue = queue; new Thread(this, name).start(); } public void run() { Random r = new Random(); while(true) { if(!queue.isSet()) { queue.enqueue(r.nextInt() % 100); } } } } Main :
import syncpcwn.*; /** * Created by Administrator on 27/07/2015. */ public class Program { public static void main(String[] args) { SyncQueue queue = new SyncQueue(); new Producer(queue, "PROCUDER"); new Consumer(queue, "CONSUMER"); } } The problem here, is that if isSet method is not synchronized , i got an ouput like that :
97, 55 and the program just continue running without outputting any value. while if isSet method is synchronized the program work correctly.
i don't understand why, there is no deadlock, isSet method just query the set instance variable without setting it, so there is no race condition.
volatilefor thesetfield to ensure visibility. Otherwise the CPU is allowed to store it in the cache / register and not update it as an optimization.synchronizedhas the same visibility results, which in hardware is a store memory barrier. I recommend readingJava Concurrency in Practicefor a gentle introduction. You'll learn abouthappens-beforeandroach motel model, without getting lost in the hardware details (barriers, MESI protocol, etc).setfield is fresh (not from cache). Thevolatilekeyword causes a memory barrier to be inserted for every read and write operation. Thesynchronizedkeyword causes a monitor lock to be acquired and then released, and acquiring a monitor also inserts a memory barrier. More pedantically, you need a happens-before relationship between the write tosetinenqueueanddequeueand the read inisSet; you can read the Java Language Spec to find all the ways a happens-before relationship can be established.volatileorsynchronizedas others have mentioned, but in general, you would want to surround the whole operation with a synchronized block. Otherwise, if you had 2 consumers, for example, both could checkisSet()at the same time, see that there is a value there, then both try to dequeue the same value. This would happen in the case where a thread switch occurred between isSet() and dequeue(), and synchronizing both methods would not help you.