3

I am learning about synchronized methods as a means of preventing race conditions and unwanted behavior in Java. I was presented with the following example, and told the race condition is quite subtle:

public class Messages { private String message = null; private int count = 2; // invariant 0 <= count && count <= 2 public synchronized void put(String message) { while( count < 2 ) this.wait(); this.message = message; this.count = 0; this.notifyAll(); } public synchronized String getMessage() { while( this.count == 2 ) this.wait(); String result = this.message; this.count += 1; this.notifyAll(); return result; } } 

Subtle or not, I think I have a fundamental misunderstanding of what synchronized methods do. I was under the impression they restrict access to threads through use of a lock token (or similar), and thus can never race. How, then, does this example have a race condition, if its methods are synchronized? Can anyone help clarify?

1
  • 1
    I'm always tempted to blindly answer "yes" to questions like this (just based on the title). Commented Apr 7, 2014 at 21:27

6 Answers 6

2

I presume that what the author had in mind is that, since count goes from 0 to 2, two threads might call put() in sequence, and the reader threads would thus miss one of the messages.

It's indeed a race condition: readers and putters compete for the same lock, and if the messages being read depends on which thread is notified by notifyAll().

Sign up to request clarification or add additional context in comments.

3 Comments

Can you elaborate on the interleaving that breaks the OP's example? I've been trying to find one since I was curious and I was unable to. If two separate threads call put, then the first one will set count = 0, and the second will wait().
Hmm, you're right. @Rome_Leader can you please unaccept this answer, so that I can delete it. Sorry.
Please explain a little more with sample code.i couldn't understand how the race condition is achieved.
1

Think about ways that count could become > 2...

That code has a bad smell, too. What is count supposed to be counting? Why does get increment it and put reset it? Why the unnecessary use of 'this'? If I saw code like that in a project, I would look at it very carefully...

1 Comment

As a standalone race condition example, I assume it's not meant to be perfect. I was just trying to analyze it. Your pointer makes sense, I think, and seems to be in line with what I'm now thinking, based on my comment on another answer! Thanks!
1

Multi threading is when you use new Thread(runnable).start(); this starts a new thread and goes to the run() method. The runnable is any class that implements runnable. Or extends thread a synchronized method makes sure that if these threads want to read data changed by the synchronized method it will be possible, otherwise it might be unchanged, or worse, half-changed.

Comments

1

Java's synchronized methods buys you mutual exclusion between the two methods, which means that you can assume they will not interleave.

However, you still have a race condition because you can get different behavior depending on which method runs first.

As JB Nizet suggested in his answer, consider what happens with each of the two orderings (assume they are running in different threads).

2 Comments

Ahhh, I think I see. The order is significant, because count is initialized to 2, getMessage will go first. Its wait will release the lock, and, while it is trying to get the message, the message will never be loaded by put?
Please explain a little more clearly with sample code.
0

A race condition occurs whenever two entities compete for a single resource, which can cause unpredictable behavior if the outcome depends on the order. When you use notifyAll() all threads are woken up and they race to obtain the lock they were waiting for, and it's impossible to say which will execute next.

1 Comment

Pleae explain the solution with little sample code scenario.
0

I don't think having a count value >2 is the problem if the code can work as expected. Since both put() and getMessage() methods are synchronized both method's can't be called at the same time. So if an thread calls getMessage() and has the count value 2, another thread can't call the put() method to set the count = 0 and notify the waiting thread.There is too much synchronizing, which cause an deadlock. So the while part shouldn't be synchronized and can solved like this.

 public void put(String message) { while( count < 2 ) this.wait(); synchronzied(this){ this.message = message; this.count = 0; this.notifyAll(); } } public String getMessage() { while( this.count == 2 ) this.wait(); synchronized(this){ String result = this.message; this.count += 1; this.notifyAll(); } return result; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.