synchronized&Object类的wait/notify/notifyAll(生产者消费者场景)

Java中的每一个对象都有一个监视器

Object类的wait和notify、notifyAll方法必须在synchronized块中调用

调用一个对象的notify、notifyAll方法时,当前线程必须持有该对象的监视器monitor,否则抛出IllegalMonitorStateException

如果在synchronized块中调用另一个对象的notify、notifyAll方法,由于持有的对象的监视器不同,抛出IllegalMonitorStateException


(1)synchronized块

       synchronized(lock){

  }

  synchronized块中的方法,获得了lock实例的monitor


(2)实例synchronized方法

  public synchronized void run() {

  }

  获得了this对象的monitor

(3)静态synchronized方法

  public static synchronized void run() {

  }

  获得了当前类的所有对象的monitor


(1)wait()

一个持有当前对象的monitor的线程调用了当前对象的空参的wait方法,使得当前线程进入WARTING状态,释放锁

必须等待另一个持有当前对象的monitor的线程调用当前对象的notify或者notifyAll方法将该线程唤醒

 

(2)wait(long)

 norify

notifyAll

等待时间到

interrupt

(3)wait(long,int)

  

  wait方法必须总是存在于循环中

  

生产者、消费者场景

/**
 * @author DuanJiaPing
 * @date 2018/6/11 9:08
 *
 * 等待喚醒機制
 *
 *
 * Object類的方法
 * wait()
 * notify()
 * notifyAll()
 *
 * 生產者和消費者案例
 * 生產者生產的產品給店員,消費者從店員那獲取產品
 *
 * 生产者线程:创建和添加数据的线程
 * 消费者线程:删除和销毁数据的线程
 *
 * 生产者消费者案例不使用等待唤醒机制
 * 会产生以下问题
 * 数据丢失:生产者线程过快,另一面接受不到
 * 数据重复:消费者线程过快
 *
 *
 * 问题:程序结束不了
 * wait():等在方法调用处,并释放锁,当被notify或notifyAll方法唤醒之后,在等待的位置处继续执行
 * 线程被唤醒之后,被唤醒的线程和唤醒线程的线程同时抢锁
 * 解决:把notifyAll方法移到else之外
 *
 * 虚假唤醒问题:
 * 当前库存超过了最大库存或者小于0的情况
 * 解决:
 * Java API
 * wait()方法提示:应当将wait方法总是放在循环中
 *
 */
public class TestProductorAndConsumer {


    public static void main(String[] args){
        Clerk clerk = new Clerk();
        Productor productor = new Productor(clerk);
        Consumer consumer = new Consumer(clerk);

        new Thread(productor,"生产者A").start();
        new Thread(productor,"生产者B").start();
        new Thread(consumer,"消费者1").start();
        new Thread(consumer,"消费者2").start();

    }


}

/*
* 店员类
* 店员进货、售货,只有一个店员
* */

class Clerk{

    /*库存*/

    private int product = 0;

    /*
    * 此时,进货和售货的两个方法都操作共享数据product(库存)
    * 因此,这两个方法都存在线程安全问题
    * 解决:同步方法,同步代码块
    *
    * */

    /*
    * 进货
    * */

    public synchronized void get(){

        while (product >= 5) {
            System.out.println("库存已满");
            try{
                //将wait放在while循环中,当多个线程在此处等待,并被notifyAll唤醒之后,会再循环判断一次product的值
                wait();
            }catch(Exception e){

            }
        }
//        if(product >= 1) {
//            System.out.println("库存已满");
//            try{
//                wait();//当两个线程同时wait在此处,notifyAll之后,两个线程都从这块开始执行,都执行下面的sysout,都将product(库存)加一
//            }catch(Exception e){
//
//            }
//        }

        /*else{
            System.out.println(Thread.currentThread().getName()+"--进货--当前库存--"+ ++product);

            notifyAll();
        }*/

        System.out.println(Thread.currentThread().getName()+"--进货--当前库存--"+ ++product);

        notifyAll();

    }

    /*
    * 售货
    * */

    public synchronized void sale(){
        while(product <= 0){
            System.out.println("库存不足");
            try{
                wait();
            }catch(Exception e){

            }
        }

        System.out.println(Thread.currentThread().getName()+"--售货--当前库存--"+ --product);

        notifyAll();
    }
}


/*生产者类,生产者生产产品提供给店员
* 生产者有多个
* 多线程
* */

class Productor implements Runnable{
    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        //不断生产10个产品,提供给店员
        try{
            Thread.sleep(200);
        }catch (Exception e){

        }

        for(int i=1;i<=10;i++){
            clerk.get();
        }
    }
}


/*消费者类
* 消费者从店员处购买产品
* 多个消费者
* 多线程*/

class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            clerk.sale();
        }

    }
}



原文地址:https://www.cnblogs.com/duanjiapingjy/p/9432825.html