wait(),notify(),notifyAll() method and Condition interface in java concurrency

Keywords: Java

  • Brief introduction of methods
    wait() method: When a task encounters a call to wait() in the method, the execution of the thread is suspended and the lock is released. So another task can get the lock. That's why you should call this method in a synchronized block of code or synchronized method
    notify()/notifyAll() method: Make the waiting thread regain the lock, resume execution from wait(), notify() will randomly restore a waiting thread, and notifyAll() method will restore all waiting threads.
    Note: Just because a thread is awakened does not mean that it immediately acquires the lock of the object. Only after calling notify() or notifyAll() and exiting the synchronized block, releasing the lock of the object, and having to finish the task of the current thread, can the other threads acquire the lock execution.

  • A simple example

            public class Test {
                public static Object object = new Object();
                public static void main(String[] args) {
                    Thread1 thread1 = new Thread1();
                    Thread2 thread2 = new Thread2();
    
                    thread1.start();
    
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    thread2.start();
                }
    
    
                static class Thread1 extends Thread{
                    @Override
                    public void run() {
                        synchronized (object) {
                            try {
                                object.wait();
                            } catch (InterruptedException e) {}
                            System.out.println("thread"+Thread.currentThread().getName()+"Locks were acquired");
                        }
                    }
                }
    
    
                static class Thread2 extends Thread{
                    @Override
                    public void run() {
                        synchronized (object) {
                            object.notify();
                            System.out.println("thread"+Thread.currentThread().getName()+"Called object.notify()");
                        }
                        System.out.println("thread"+Thread.currentThread().getName()+"Release the lock.");
                    }
                }
            }
    thread1 After the task is executed, it will be suspended, and then thread2 Execute tasks, wake up thread 1, but thread2 After the synchronization block and tasks have to be executed, thread1 Can from wait()Mid recovery
    
  • Using wait()/notify() method to simulate producers and consumers
    Producer:

            import java.util.ArrayList;
    
            /**
             * @author hetiantian
             * Simulated producers produce food
             */
            public class Producer implements Runnable {
                //It can only produce five at a time, and if it reaches five, it will have to wait for consumers to eat it before they can continue to produce.
                private static ArrayList<Food> foods = new ArrayList<>(5);
                static int id;  //Object mark
    
                public Producer(ArrayList<Food> foods) {
                    this.foods = foods;
                }
    
                //Simulated production process
                public static void productFood() throws InterruptedException {
                    while (true) {
                        Food f = new Food(id++);
    
                        synchronized (foods) {
                            if (foods.size() >= 5) {
                                foods.wait();  //If it is greater than or equal to 6, it will be suspended and the next operation will continue only after it has been consumed.
                            } else {
                                foods.add(f);
                                System.out.println("Production:" + f);
                            }
                        }
    
                    }
                }
    
                @Override
                public void run() {
                    try {
                        productFood();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
    //Consumer:
    
        import java.util.ArrayList;
    
        /**
         * @author hetiantian
         * Analog consumer threads
         */
        public class Consumer implements Runnable {
            private static ArrayList<Food> foods = new ArrayList<>(5);
    
            public Consumer(ArrayList<Food> foods) {
                this.foods = foods;
            }
    
            public static void eatFood() throws InterruptedException {
                while (true) {
                    int last = foods.size() - 1;
                    Food f;
    
                    synchronized (foods) {
                        if (last < 0) {
                            foods.notify();  //If it's eaten up, release the lock and let the producer continue to execute it.
                        } else {
                            f = foods.get(last);
                            System.out.println("Consumption:" + f);
                            foods.remove(last);
                        }
                    }
    
                }
    
            }
    
            @Override
            public void run() {
                try {
                    eatFood();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    //Test class:
    
    import java.util.ArrayList;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author hetiantian
     * Consumer Producer Testing Class
     */
    public class ProductAndConsumerTest {
        private static ArrayList<Food> foods = new ArrayList<>(5);
        public static void main(String[] args) throws InterruptedException {
    
    
            Producer p = new Producer(foods);
            Consumer c = new Consumer(foods);
    
    
            ExecutorService es = Executors.newCachedThreadPool();
            es.execute(p);
            es.execute(c);
            TimeUnit.SECONDS.sleep(7);
            //Close task
            es.shutdownNow();
    
    
        }
    }
    
  • Condition briefly introduces:
    Condition's await() and signal() are more secure and efficient ways to achieve inter-thread collaboration. await() in Conditon corresponds to wait() in Object, signal() in Condition corresponds to notify() in Object, signalAll() in Condition corresponds to notifyAll() in Object. Therefore, Condition is more recommended.
    Condition relies on the Lock interface, and the basic code for generating a Condition is lock.newCondition().
    Calling Condition's await() and signal() methods must be protected by lock, that is, between lock.lock() and lock.unlock.

Posted by meshi on Fri, 15 Feb 2019 00:15:19 -0800