Waiting () / notify ()

I am trying to check how wait / notify works in java.

The code:

public class Tester { public static void main(String[] args) { MyRunnable r = new MyRunnable(); Thread t = new Thread(r); t.start(); synchronized (t) { try { System.out.println("wating for t to complete"); t.wait(); System.out.println("wait over"); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MyRunnable implements Runnable { public void run() { System.out.println("entering run method"); synchronized (this) { System.out.println("entering syncronised block"); notify(); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("leaving syncronized block"); } System.out.println("leaving run method"); } } 

Returned result

 wating for t to complete entering run method entering syncronised block //sleep called leaving syncronized block leaving run method wait over 

I expected that when notification () is executed, the wait will end and System.out.println("wait over"); will be printed. But it seems that it only prints when t finished its run() .

+8
java multithreading synchronization
source share
3 answers

The object monitor lock must be performed by one link with the same lock ...

In your example, you are waiting in an instance of Thread , but using notify from Runnable . Instead, you should use one common lock object ... for example

 public class Tester { public static final Object LOCK = new Object(); public static void main(String[] args) { MyRunnable r = new MyRunnable(); Thread t = new Thread(r); t.start(); synchronized (LOCK) { try { System.out.println("wating for t to complete"); LOCK.wait(); System.out.println("wait over"); } catch (InterruptedException e) { e.printStackTrace(); } } } public static class MyRunnable implements Runnable { public void run() { System.out.println("entering run method"); synchronized (LOCK) { System.out.println("entering syncronised block"); LOCK.notify(); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("leaving syncronized block"); } System.out.println("leaving run method"); } } } 

Output...

 wating for t to complete entering run method entering syncronised block leaving syncronized block wait over leaving run method 

wait over and leaving run method can change positions depending on the flow planning.

You can try to put a dream towards the synchronized block. This will disable the monitor lock, which allows the wait section to continue working (since it cannot start until the lock is released).

  public static class MyRunnable implements Runnable { public void run() { System.out.println("entering run method"); synchronized (LOCK) { System.out.println("entering syncronised block"); LOCK.notify(); System.out.println("leaving syncronized block"); } try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("leaving run method"); } } 
+9
source share

Response to updated code:

From Thread.sleep () javadoc:

Causes the current executable thread to sleep (temporarily stop execution) for a given number of milliseconds, taking into account the accuracy and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors .

If you call Thread.sleep while inside the synchronized block, other threads will not be able to enter the synchronized block. To avoid this, you should never complete time-consuming tasks, but in a synchronized block.

+5
source share

Please note (as others have pointed out) that you must use the same object to lock / sync in both threads.

If you want your main thread to continue immediately after calling notify , you should temporarily abandon the lock. Otherwise, wait will be called only after the secondary thread leaves the synchronized block. And it is never recommended to keep the lock in a long calculation!

One way to achieve this is to use wait(int) to block instead of sleep , because wait temporarily temporarily blocks synchronization:

 public class Tester { private static final Object lock = new Object(); public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); synchronized (lock) { try { System.out.println("wating for t to complete"); lock.wait(); System.out.println("wait over"); } catch (InterruptedException e) { e.printStackTrace(); } } } static class MyRunnable implements Runnable { public void run() { System.out.println("entering run method"); synchronized (lock) { System.out.println("entering syncronised block"); lock.notify(); try { lock.wait(1000); // relinquish the lock temporarily } catch (InterruptedException ex) { System.out.println("got interrupted"); } System.out.println("leaving syncronized block"); } System.out.println("leaving run method"); } } } 

However, the use of these low-level primitives can be very error prone, and I will not discourage their use. Instead, I suggest you use the high level Java primitives for this. For example, you can use CountDownLatch , which allows one thread to wait until the other threads go to zero:

 import java.util.concurrent.*; public class TesterC { private static final CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); System.out.println("wating for t to complete"); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("wait over"); } static class MyRunnable implements Runnable { public void run() { System.out.println("entering run method"); try { latch.countDown(); Thread.sleep(1000); } catch (InterruptedException ex) { System.out.println("got interrupted"); } System.out.println("leaving run method"); } } } 

Here you do not need to synchronize anything, the latch does everything for you. There are many other primitives you can use: semaphores, exchangers, threads with security, etc. Explorer java.util.concurrent .

Perhaps even a better solution is to use a higher-level API, such as Akka . There you work with Actors or Transactional Programming Memory , which can easily compile and save you most concurrency problems.

+1
source share

All Articles