线程间通信之wait和notify

synchronized

解释:java语言的一个关键字

作用:实现同步机制,控制多线程的访问,确保同一时刻只有一个线程可以进入临界区执行同步代码。

用法:加在代码块上、加在方法上、加在一个对象,

原理:不管是那种用法,都会有一个对象(指定的对象、class的实例对象、class对象),这个对象又会一一对应一个监视器对象,然后对监视器对象加锁,编译成字节码后,会有monitorenter和monitorexit标记同步代码块的入口和出口

监视器对象(ObjectMonitor)里有一些变量,记录一些信息

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;   // 重入次数
    _waiters      = 0,   // 等待线程数
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;  // 当前持有锁的线程
    _WaitSet      = NULL;  // 调用了 wait 方法的线程被阻塞 放置在这里
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; // 等待锁 处于block的线程 有资格成为候选资源的线程
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
}

 

wait

解释:是Object类的一个final方法,会抛出InterruptedException

作用:让当前线程进入等待状态,并释放持有的锁

原理:会将当前线程加入ObjectMonitor的_WaitSet,当前线程随即释放锁,并等待在原地,停止执行后续代码

用法:使用synchronized包裹,抛出或者处理中断异常

    public void doWait() throws InterruptedException {
        synchronized (obj) {
            obj.wait();
        }
    }

 

 

notify

解释:是Object类的一个final native方法

作用:随机唤醒一个线程,这个线程是waiting在当前object的monitor,即加入ObjectMonitor的_WaitSet的线程

原理:从ObjectMonitor的_WaitSet中随机取出一个线程唤醒,这个线程随即获取锁,继续执行后续的代码

用法:使用synchronized包裹

    public void doNotify() {
        synchronized (obj) {
            obj.notify();
        }
    }

 

notifyAll

同notify,只不过唤醒所有的等待线程,所有的等待线程随即竞争同步锁

 

下面是一个经典的生产者消费者模型,由于是多个生产者多个消费者,在此,在仓库满了以后,我们使用wait让生产者进入等待,在仓库空了以后让消费者进入等待。当生产者将商品放入仓库以后,通知等待的消费者继续消费 或者 当消费者消费了商品以后,通知等待的生产者继续生产,此处由于是多个生产者和多个消费者,如果使用nofity,可能唤醒的不是想要唤醒的线程。 但是使用notifyAll,需要做一个保护,下面代码中的while。  在仓库满了以后,如果唤醒的生产者竞争到了锁,还是会将商品放入了仓库,导致仓库爆了,或者  在仓库空了以后,如果唤醒的消费者竞争到了锁,会消费不到商品。

public class Test {
    public static void main(String[] args) {
        new Test().start();
    }
    private void start(){
        Store store = new Store(10);
        Thread producer1 = new Thread(new Producer("producer1",store, 1000));
        Thread producer2 = new Thread(new Producer("producer2",store, 1000));
        Thread consumer1 = new Thread(new Consumer("consumer1",store, 1000));
        Thread consumer2 = new Thread(new Consumer("consumer2",store, 1000));
        Thread consumer3 = new Thread(new Consumer("consumer3",store, 1000));
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }

    class Store {
        final int capacity;
        final List<String> list;
        public Store(int capacity){
            this.capacity = capacity;
            list = new ArrayList<>(capacity);
        }
        public String take() throws InterruptedException {
            synchronized (list) {
                while (list.isEmpty()) { // prevent consumer notify consumer, so use while
                    list.wait();
                }
                String product = list.remove(list.size() - 1);
                list.notifyAll();
                return product;
            }
        }
        public void add(String product) throws InterruptedException {
            synchronized (list) {
                while (list.size() >= capacity) { // prevent producer notify producer, so use while
                    list.wait();
                }
                list.add(product);
                list.notifyAll();
            }
        }
    }
    class Producer implements Runnable{
        String flag;
        Store store;
        int interval;
        public Producer(String flag, Store store, int interval) {
            this.flag = flag;
            this.store = store;
            this.interval = interval;
        }
        @Override
        public void run() {
            for(long i=0;;i++) {
                try {
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    System.out.println("sleep InterruptedException so finish thread "+flag);
                    break;
                }
                String product = "product-"+flag+"-"+i;
                System.out.println(flag+" produce "+product);
                try {
                    store.add(product);
                } catch (InterruptedException e) {
                    System.out.println("wait/notify InterruptedException so finish thread "+flag);
                    break;
                }
            }
        }
    }
    class Consumer implements Runnable{
        String flag;
        Store store;
        int interval;
        public Consumer(String flag, Store store, int interval) {
            this.flag = flag;
            this.store = store;
            this.interval = interval;
        }
        @Override
        public void run() {
            for(;;) {
                try {
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    System.out.println("sleep InterruptedException so finish thread "+flag);
                    break;
                }
                try {
                    String product = store.take();
                    System.out.println(flag+" consume "+product);
                } catch (InterruptedException e) {
                    System.out.println("wait/notify InterruptedException so finish thread "+flag);
                    break;
                }
            }
        }
    }
}

  

 

posted @ 2024-04-02 16:13  坏男银  阅读(5)  评论(0编辑  收藏  举报