Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

synchronized method while using wait()

I ran the following code:

class Counter extends Thread {

 static int i=0;
//method where the thread execution will start
public void run(){
    //logic to execute in a thread

    while (true) {
        increment();
    }
}

public synchronized void increment()  {
    try {
        System.out.println(this.getName() + " " +  i++);
        wait(1000);
        notify();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
//let’s see how to start the threads
public static void main(String[] args){
    Counter c1 = new Counter();
    Counter c2 = new Counter();
    c1.setName("Thread1");
    c2.setName("Thread2");
    c1.start();
    c2.start();
}
}

The result of this code was (added line numbers):

1: Thread1 0
2: Thread2 1
3: Thread2 2
4: Thread1 3
5: Thread2 4
6: Thread1 4
7: Thread1 5
8: Thread2 6
stopping...

Since increment method is synchronized and since it contains wait(1000) I didnt expect: 1. Thread2 to print 2 consecutive prints: lines 2,3 I expected the threads to interleave their prints 2. on lines 5,6 the i remains 4.

could anyone give me an explanation for this?

like image 557
Elad Avatar asked May 19 '12 12:05

Elad


People also ask

Why must wait () always be in synchronized block?

As Michael Borgwardt points out, wait/notify is all about communication between threads, so you'll always end up with a race condition similar to the one described above. This is why the "only wait inside synchronized" rule is enforced.

Is it possible to call the wait () method in a non synchronized block?

If you need to call wait(), notify(), or notifyAll() from within a non-synchronized method, then you must first obtain a lock on the object's monitor. If you don't, an exception will be generated when an attempt is made to call the method in question.

Does wait () Release lock from synchronized block?

The wait function doesn't release "all locks", but it does release the lock associated with the object on which wait is invoked.

Why wait () notify () and notifyAll () methods have to be called from a synchronized method or block?

The wait(), notify(), and notifyAll() methods should be called for an object only when the current thread has already locked the object's lock. This point sometimes goes unnoticed because programmers are used to calling these methods from within synchronized methods or blocks. Otherwise, you will get "java.


2 Answers

Synchronized instance methods like this:

public synchronized void foo() { 
    ... 
}

are roughly equivalent to:

public void foo() {
   synchronized(this) {
       ...
   }
}

Do you see the problem here? The synchronization is done on the current instance.

Since you are creating two separate Thread objects each increment method will synchronize on a different object, thus rendering the lock useless.

You should either make your increment method static (thus the locking is done on the class itself) or use a static lock object:

private static final Object locker = new Object();

public void foo() {
   synchronized(locker) {
       ...
   }
}

And one final advice: the preferred way to create a thread in java is by implementing Runnable, not extending Thread.

like image 73
Tudor Avatar answered Oct 18 '22 20:10

Tudor


You are only synchronizing at the instance level. To synchronize across all Counter instances you need the increment method to be static as well as synchronized.

As it stands all your threads run freely, concurrent with each other, because they share no synchronization mechanism.

like image 1
Steve Townsend Avatar answered Oct 18 '22 20:10

Steve Townsend