Is there example implementation of Peterson algorithm for mutual exclusion in Java?
Is there example implementation of Peterson algorithm for mutual exclusion in Java?
Share
Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.
Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.
Lost your password? Please enter your email address. You will receive a link and will create a new password via email.
Please briefly explain why you feel this question should be reported.
Please briefly explain why you feel this answer should be reported.
Please briefly explain why you feel this user should be reported.
No one here has provided a correct/safe implementation of this algorithm in Java. I’m not sure how John W’s solution is supposed to work since it’s got pieces missing (namely the declarations of the ThreadLocals and an explanation of what is supposed to be in his array—primitive
booleansdon’t haveget()andset()).Chapter 17 of the Java Language Specification explains the Java memory model. Of particular interest is Section 17.4.5, which describes the happens-before order. It’s pretty easy to think about within a single thread. Consider the snippet:
Everyone will agree that at the end of this snippet, both
xandzare equal to0and bothyandware equal to5. Ignoring the declarations, we have six actions here:xyxzywBecause they all appear in the same thread, the JLS says that these reads and writes are guaranteed to exhibit this ordering: each action n above (because the actions are in a single thread) has a happens-before relationship with all actions m, m > n.
But what about different threads? For normal field accesses, there are no happens-before relationships established between threads. This means a Thread A could increment a shared variable and Thread B might read that variable but not see the new value. In the program’s execution in the JVM, the propagation of Thread A’s write may have been reordered to happen after Thread B’s read.
In fact, Thread A could write to a variable
x, and then to a variabley, establishing a happens-before relationship between those two actions within Thread A. But Thread B may readxandyand it is legal for B to get the new value ofybefore the new value ofxappears. The spec says:How do we fix this? For normal field accesses, the
volatilekeyword is enough:synchronizes-with is a stronger condition than happens-before, and since happens-before is transitive, if Thread A wants Thread B to see its writes to
xandy, it just needs to write to a volatile variablezafter writingxandy. Thread B needs to read fromzbefore readingxandyand it will be guaranteed to see the new values ofxandy.In Gabriel’s solution, we see this pattern: a write occurs to
in, which would not be visible to other threads, but then a write occurs toturn, so other threads are guaranteed to see both writes as long as they readturnfirst.Unfortunately, the while loop’s conditional is backwards: to guarantee a thread does not see stale data for
in, the while loop should read fromturnfirst:With this fix in mind, most of the rest of the solution is ok: in the critical section, we don’t care about staleness of data because, well, we’re in the critical section! The only other flaw comes at the end: the Runnable sets
in[id]to a new value and exits. Will the other Thread be guaranteed to see the new value ofin[id]? The spec says no:So how do we fix it? Just add another write to
turnat the end of the method:Since we reordered the while loop, the other thread will be guaranteed to see the new false value of
in[id]because the write toin[id]happens-before the write toturnhappens-before the read fromturnhappens-before the read fromin[id].Needless to say, without a metric ton of comments, this method is brittle and someone could come along and change something and subtly break the correctness. Just declaring the array
volatileis not good enough: as explained in this thread by Bill Pugh (one of the lead researchers for the Java memory model), declaring an arrayvolatilemakes updates to the array reference visible to other threads. Updates to array elements are not necessarily visible (hence all the loops we just had to jump through by using anothervolatilevariable to guard access to the array elements).If you want your code to be clear and concise, keep it the way it is and change
into be an AtomicIntegerArray (use 0 for false, 1 for true; there is no AtomicBooleanArray). This class acts like an array whose elements are allvolatile, and so will solve all our problems nicely. Alternatively, you could just declare two volatile variables,boolean in0andboolean in1, and update them instead of using a boolean array.