• 线程间通信 Object/wait(),notify() 和 Lock/Condition/await(),signal()


    基本前提知识:

    一:Object/wait(), notify(), notifyAll()

      1:wait() 方法暂停当前线程,并立即释放对象锁;

      2:notify()/notifyAll() 方法唤醒其他等待该对象锁的线程,并在执行完同步代码块中的后续步骤后,释放对象锁

      3:notify()和notifyAll()的区别在于:

          notify只会唤醒其中一个线程,
            notifyAll则会唤醒全部线程。
        
        至于notify会唤醒哪个线程,是由线程调度器决定的。

    例子:

    public class TestWaitAndnotify {
    
        public static void main(String[] args) {
            demo2();
        }
        
        public static void demo2 () {
            final Object lock = new Object();
            Thread A = new Thread(new Runnable(){
    
                @Override
                public void run() {
                    System.out.println("INFO: A 等待锁 ");
                    synchronized (lock) {
                        System.out.println("INFO: A 得到了锁 lock");
                        System.out.println("A1");
                        try {
                            System.out.println("INFO: A 准备进入等待状态,放弃锁 lock 的控制权 ");
                            lock.wait();//挂起线程A 放弃锁 lock 的控制权
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("INFO: 有人唤醒了 A, A 重新获得锁 lock");
                        System.out.println("A2");
                        System.out.println("A3");
                    }
                }
            });
            
            Thread B = new Thread(new Runnable() {
    
                @Override
                public void run() {
                     System.out.println("INFO: B 等待锁 ");
                    synchronized (lock) {
                        System.out.println("INFO: B 得到了锁 lock");
                        System.out.println("B1");
                        System.out.println("B2");
                        System.out.println("B3");
                        System.out.println("INFO: B 打印完毕,调用 notify 方法 ");
                        lock.notify(); // notify()方法唤醒正在等待lock锁的线程A
                        System.out.println("线程 B do notify method 完毕");
                    }
                }
            });
            
            A.start();
            B.start();
        } 
    }

    输出:

    题外话: notify()方法唤醒等待锁对象的其他线程,这个notify()方法需要先执行完自己线程的后续代码,才会接着执行被唤醒的那个线程的代码,修改上面的例子看一下:

    public class TestWaitAndnotify {
    
        public static void main(String[] args) {
            demo2();
        }
        
        public static void demo2 () {
            final Object lock = new Object();
            Thread A = new Thread(new Runnable(){
    
                @Override
                public void run() {
                    System.out.println("INFO: A 等待锁 ");
                    synchronized (lock) {
                        System.out.println("INFO: A 得到了锁 lock");
                        System.out.println("A1");
                        try {
                            System.out.println("INFO: A 准备进入等待状态,放弃锁 lock 的控制权 ");
                            lock.wait();//挂起线程A 放弃锁 lock 的控制权
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("INFO: 有人唤醒了 A, A 重新获得锁 lock");
                        System.out.println("A2");
                        System.out.println("A3");
                    }
                }
            });
            
            Thread B = new Thread(new Runnable() {
    
                @Override
                public void run() {
                     System.out.println("INFO: B 等待锁 ");
                    synchronized (lock) {
                        System.out.println("INFO: B 得到了锁 lock");
                        System.out.println("B1");
                        System.out.println("B2");
                        System.out.println("B3");
                        System.out.println("INFO: B 打印完毕,调用 notify 方法 ");
                        lock.notify(); // notify()方法唤醒正在等待lock锁的线程A
                        try {
                            Thread.sleep(10000); // 睡眠10秒钟
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程 B do notify method 完毕");
                    }
                }
            });
            
            A.start();
            B.start();
        } 
    }

    打印完:INFO: B 打印完毕,调用 notify 方法  后面等待了10秒钟才开始执行。wait()方法是要等待notify()后续的代码才能开始。

    生产者消费者例子:

    import java.util.LinkedList;
    import java.util.Queue;
    
    public class ProducerAndConsumer {
        
        private final int MAX_LEN = 3;
        private Queue<Integer> queue = new LinkedList<Integer>();
        
        class Producer extends Thread {
            @Override
            public void run() {
                producer();
            }
            
            private void producer() {
                while(true) {
                    synchronized (queue) {
                        if(queue.size() == MAX_LEN) {
                            System.out.println("当前队列满");
                            queue.notify();
                            try {
                                queue.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        queue.add(1);
                        queue.notify();
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("生产者又生产一条任务,当前队列长度为" + queue.size());
                        
                    }
                }
            }
        }
        
        class Consumer extends Thread {
            @Override
            public void run() {
                consumer();
            }
            private void consumer() {
                while(true) {
                    synchronized (queue) {
                        if(queue.size() == 0) {
                            System.out.println("当前队列为空");
                            queue.notify();
                            try {
                                queue.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            
                        }
                        queue.poll();
                        queue.notify();
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("消费者消费了一条任务,当前队列长度为" + queue.size());
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            ProducerAndConsumer pac = new ProducerAndConsumer();
            
            Producer producer = pac.new Producer();
            Consumer consumer = pac.new Consumer();
            producer.start();
            consumer.start();
        }
    }

    一:Lock/condition/await(), signal(), signalAll()

    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ProducerAndConsumer1 {
        
        private final int MAX_LEN = 3;
        private Queue<Integer> queue = new LinkedList<Integer>();
    
        final Lock lock = new ReentrantLock();
        final Condition producerSignal = lock.newCondition();
        final Condition consumerSignal = lock.newCondition();
    
        class Producer extends Thread {
            @Override
            public void run() {
                producer();
            }
            
            private void producer() {
                while(true) {
                    lock.lock();
                    try {
                        if(queue.size() == MAX_LEN) {
                            System.out.println("当前队列满");
                            try {
                                consumerSignal.signal();
                                producerSignal.await();    
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        queue.add(1);
                        consumerSignal.signal();
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("生产者生产了一条任务,当前队列长度为" + queue.size());
                        
                    } finally {
                        lock.unlock();
                    }
                }
    
            }
        }
        
        class Consumer extends Thread {
            @Override
            public void run() {
                consumer();
            }
            
            private void consumer() {
                while(true) {
                    lock.lock();
                    try {
                        if(queue.size() == 0) {
                            System.out.println("当前队列为空");
                            try {
                                producerSignal.signal();
                                consumerSignal.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        queue.poll();
                        producerSignal.signal();
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("消费者消费了一条任务,当前队列长度为" + queue.size());
                        
                    } finally {
                        lock.unlock();
                    }
                }
    
            }
        }
        
        public static void main(String[] args) {
            ProducerAndConsumer1 pac = new ProducerAndConsumer1();
            
            Producer producer = pac.new Producer();
            Consumer consumer = pac.new Consumer();
            producer.start();
            consumer.start();
        }
    
    }

    分析: 这里共享的变量是queue,生产者消费者都需要修改这个queue,为了保证安全,需要一个个的来,用lock,lock()就保证了每次只有一个线程来操作queue;

       在生产和消费的时候,需要关心queue.size()的大小,如果满了,就不能生产,这里用了producerSignal.await(),让生产者放弃锁,去等待消费者去消费,consumerSignal.signal()去唤醒消费者去消费,如果空了,就不能消费, 这里用consumerSignal.await(),让消费者放弃锁,去等待生产者去生产,producerSignal.signal()去唤醒生产者去生产。

  • 相关阅读:
    python3 bytes数据类型探讨
    字典
    列表及元组
    在py文件中设置文件头
    函数的作用域、global与nonlocal
    python中 的意义及用法
    int、bool和str
    while循环、格式化输出、运算符和编码初识
    python初认识、基础数据类型以及 if 流程控制
    列表遍历和生成器遍历效率对比
  • 原文地址:https://www.cnblogs.com/myseries/p/12103723.html
Copyright © 2020-2023  润新知