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(); } } }