线程间通信
等待唤醒机制
-
等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下:
wait():告诉当前线程放弃执行权,并放弃监视器(锁)并进入阻塞状态,直到其他线程持有获得执行权,并持有了相同的监视器(锁)并调用notify为止。
notify():唤醒持有同一个监视器(锁)中调用wait的第一个线程,例如,餐馆有空位置后,等候就餐最久的顾客最先入座。注意:被唤醒的线程是进入了可运行状态。等待cpu执行权。
notifyAll():唤醒持有同一监视器中调用wait的所有的线程。
-
调用wait和notify方法需要注意的细节:
wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
-
waite和sleep方法的区别
相同之处:
线程调用wait()或者是sleep()方法都会进入临时阻塞状态,会释放cpu的执行权。调用时都需要处理 InterruptedException异常。不同之处:
wait(): 释放资源,释放锁。是Object的方法。
sleep():释放资源,不释放锁。是Thread的静态方法
生产者消费者
public class Container {
public static int num = 20;
}
public class Producer implements Runnable {
@Override
public void run() {
while (true) {
synchronized ("锁") {
if (Container.num < 20) {
Container.num++;
System.out.println(Thread.currentThread().getName() + "生产了一个货物,剩余" + Container.num);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (Container.num == 20) {
try {
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class Consumer implements Runnable {
@Override
public void run() {
while (true) {
synchronized ("锁") {
if (Container.num > 0) {
Container.num--;
System.out.println(Thread.currentThread().getName() + "消费了一个货物,剩余" + Container.num);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (Container.num == 0) {
"锁".notifyAll();
}
}
}
}
}
public class test {
public static void main(String[] args) {
Producer p = new Producer();
Consumer c = new Consumer();
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
IllegalMonitorStateException
抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
调用wait()和notifyAll()的锁必须是出现过的锁