wait和notify主要用在线程间的通信,
wait:让当前调用了wait的对象的所在线程堵塞,前提是当前线程获得了同步锁,不然会抛IllegalMonitorStateException异常
notify:通知调用了wait的对象继续执行,不堵塞,前提是调用了notify的对象已经出了synchronized代码块,释放了锁,才能通知成功
使用wait和notify要注意几点:
- wait和notify的调用者必须是同一个对象,只有这么才能通信
- wait和notify必须执行在synchronized代码块中,必须要加锁,不然会抛IllegalMonitorStateException异常
- wait和notify是每个对象都有的方法,是Object的方法,因为每个对象都有锁,锁是对象的基础,
- wait和notify必须用while循环,因为这个可以往复判断条件
- notify的执行必须跳出了synchronized,才能够通知到其他线程,就是要释放了自己的锁,才可以
下面是一个生产者和消费的例子:
public class MainClass {
static int num=0;
static int maxCount=5;
static int count=0;
public static void main(String args[])
{
final Object lock = new Object();
new Thread(new Runnable() {
@Override
public void run() {
String threadname=Thread.currentThread().getName();
synchronized (lock)
{
while(true)
{
while (count==maxCount)
{
try {
System.out.println(threadname+":"+"篮子里苹果满了,一共10个,需要等待被吃完了,才继续放");
lock.wait();
}
catch (InterruptedException e)
{
}
}
try {
Thread.sleep(500);
count++;
System.out.println(threadname+":"+"向篮子里添加了一个苹果,篮子里一共:"+count+"个苹果");
if(count==maxCount)
{
lock.notifyAll();
}
}
catch (InterruptedException e)
{
}
}
}
}
},"product").start();
new Thread(new Runnable() {
@Override
public void run() {
String threadname=Thread.currentThread().getName();
synchronized (lock)
{
while(num<2)
{
while (count==0)
{
try {
System.out.println(threadname+":"+"篮子里苹果空了,需要等待放满了,才继续吃");
lock.wait();
}
catch (InterruptedException e)
{
}
}
try {
Thread.sleep(500);
count--;
System.out.println(threadname+":"+"吃了了一个苹果,篮子里还剩:"+count+"个苹果");
if(count==0)
{
num++;
System.out.println(threadname+":"+"一共要吃"+2+"篮子苹果,现在吃了"+num+"篮子苹果了");
if(num<2)
{
lock.notify();
}
}
}
catch (InterruptedException e)
{
}
}
System.out.println(threadname+":"+"吃完5篮子苹果了,任务结束");
}
}
},"customer").start();
}
}
执行结果:
product:向篮子里添加了一个苹果,篮子里一共:1个苹果
product:向篮子里添加了一个苹果,篮子里一共:2个苹果
product:向篮子里添加了一个苹果,篮子里一共:3个苹果
product:向篮子里添加了一个苹果,篮子里一共:4个苹果
product:向篮子里添加了一个苹果,篮子里一共:5个苹果
product:篮子里苹果满了,一共10个,需要等待被吃完了,才继续放
customer:吃了了一个苹果,篮子里还剩:4个苹果
customer:吃了了一个苹果,篮子里还剩:3个苹果
customer:吃了了一个苹果,篮子里还剩:2个苹果
customer:吃了了一个苹果,篮子里还剩:1个苹果
customer:吃了了一个苹果,篮子里还剩:0个苹果
customer:一共要吃2篮子苹果,现在吃了1篮子苹果了
customer:篮子里苹果空了,需要等待放满了,才继续吃
product:向篮子里添加了一个苹果,篮子里一共:1个苹果
product:向篮子里添加了一个苹果,篮子里一共:2个苹果
product:向篮子里添加了一个苹果,篮子里一共:3个苹果
product:向篮子里添加了一个苹果,篮子里一共:4个苹果
product:向篮子里添加了一个苹果,篮子里一共:5个苹果
product:篮子里苹果满了,一共10个,需要等待被吃完了,才继续放
customer:吃了了一个苹果,篮子里还剩:4个苹果
customer:吃了了一个苹果,篮子里还剩:3个苹果
customer:吃了了一个苹果,篮子里还剩:2个苹果
customer:吃了了一个苹果,篮子里还剩:1个苹果
customer:吃了了一个苹果,篮子里还剩:0个苹果
customer:一共要吃2篮子苹果,现在吃了2篮子苹果了
customer:吃完5篮子苹果了,任务结束
这个就是两个线程通过wait和notify进行通知的例子,
我们知道notify的重载方法notifyAll,这个是通知所有的持有相同对象的线程,下面就是一个通知多线的例子:
public class WaitNotifyTest {
// 在多线程间共享的对象上使用wait
private String[] shareObj = {"true"};
//线程等待
class ThreadWait extends Thread{
public ThreadWait(String name){
super(name);
}
@Override
public void run() {
synchronized (shareObj){
while ("true".equals(shareObj[0])){
System.out.println("线程"+this.getName()+"开始等待");
long startTime = System.currentTimeMillis();
try {
shareObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("线程"+this.getName()+"等待的时间为"+
(endTime - startTime));
}
}
System.out.println("线程" + this.getName() + "等待结束");
}
}
//线程唤醒
class ThreadNotify extends Thread{
public ThreadNotify(String name){
super(name);
}
@Override
public void run() {
try {
// 给等待线程等待时间
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (shareObj){
System.out.println("线程" + this.getName() + "开始准备通知");
shareObj[0] = "false";
shareObj.notifyAll();
System.out.println("线程" + this.getName() + "通知结束");
try {
sleep(3000);
}
catch (InterruptedException e)
{
}
}
System.out.println("线程" + this.getName() + "运行结束");
}
}
public static void main(String[] args) {
WaitNotifyTest waitNotifyTest = new WaitNotifyTest();
ThreadWait threadWait1 = waitNotifyTest.new ThreadWait("wait thread1");
threadWait1.setPriority(2);
ThreadWait threadWait2 = waitNotifyTest.new ThreadWait("wait thread2");
threadWait2.setPriority(3);
ThreadWait threadWait3 = waitNotifyTest.new ThreadWait("wait thread3");
threadWait3.setPriority(4);
ThreadNotify threadNotify = waitNotifyTest.new ThreadNotify("notify thread");
threadNotify.start();
threadWait1.start();
threadWait2.start();
threadWait3.start();
}
}
结果:
线程wait thread1开始等待
线程wait thread3开始等待
线程wait thread2开始等待
//等待3秒
线程notify thread开始准备通知
线程notify thread通知结束
线程notify thread运行结束
//等待3秒
线程wait thread2等待的时间为6008
线程wait thread3等待的时间为6008
线程wait thread2等待结束
线程wait thread1等待的时间为6008
线程wait thread3等待结束
线程wait thread1等待结束
在上面的代码中有2点要注意:
- 给线程设置优先级setPriority,对notifyAll唤醒其他线程的先后顺序没有联系,先wait的先被唤醒
shareObj.notifyAll();
System.out.println("线程" + this.getName() + "通知结束");
try {
sleep(3000);
}
2、这里可以看出只有释放了自己的锁,才能唤醒其他线程,等待了3s,后其他线程才被唤醒,不是说调用了notify其他线程就会被唤醒,这要注意