Wait() / notify() synchronization

前端 未结 3 1197
广开言路
广开言路 2020-12-28 21:31

I\'m trying to check how wait/notify works in java.

Code:

public class Tester {
    public static void main(String[] args) {
                


        
3条回答
  •  春和景丽
    2020-12-28 22:12

    Note (as others pointed out as well) that you have to use the same object for locking/synchronizing in both threads.

    If you want your main thread to continue immediately after notify is called, you have to relinquish the lock temporarily. Otherwise wait will get called only after the secondary thread leaves the synchronized block. And it's never a good idea to keep a lock in a long running computation!

    One way how to achieve is to use wait(int) on the lock instead of sleep, because wait releases the synchronization lock temporarily:

    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, using these low-level primitives can be very error prone and I'd discourage from using them. Instead, I'd suggest you to use Java's high-level primitives for that. For example, you can use CountDownLatch which lets one thread wait until other threads count down 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 don't have to synchronize anything, the latch does everything for you. There are many other primitives you can use - semaphores, an exchanger, thread-safe queues, etc. Explorer the java.util.concurrent package.

    Perhaps even better solution is to use even higher level API, such as Akka provides. There you work with Actors or Software transactional memory, which can be composed easily and spare you of most of concurrency issues.

提交回复
热议问题