具体流程:一个线程(生产者)修改(nofity)一个对象,另一个线程(消费者)感知到变化(wait中...)开始进行操作。
作用:Java的等待/通知机制使消费者不需要循环一直监控对象是否变化,节约资源。
实现原理:使用某个对象的锁来实现,Java任意对象都具有此机制,因为表中五个方法定义在Object类上。
方法 | 说明 |
---|---|
notify() | 线程调用了某对象的notify(),并释放此对象的锁后,等待线程(调用过此对象的wait()方法)有机会(如果获取到了该对象的锁)从wait()中返回。 |
notifyAll() | notifyAll()将等待队列中的全部线程移动到同步队列,被移动的线程状态由WAITING变为BLOCKED。 |
wait() | 线程内调用了某对象的wait()后会转入waiting状态,并将此线程放置到这个对象的等待队列。 |
wait(long) | 设置等待时间,超时则跳过等待继续执行。 |
wait(long,int) | 细粒度控制超时时间。 |
锁和对象的关系:
每个java对象头中都有锁状态位标记。java中在使用synchronize同步的时候,肯定是涉及到某个对象的锁。因此,在考虑同步的时候,首先要想到是同步的是哪个对象的锁。
在java字节码上,获取了某个对象的锁之后,进入时会调用monitorenter指令,在退出时会调用monitorexit指令。可见,java object monitor是对java对象的锁的一种抽象。它和java对象是一对一的关系的。
在java中,通过java object monitor使得锁是和其保护的对象一一对应的。
只有拥有了该对象的锁,才可以调用以上5个方法,所以上述5个方法需要在synchronized代码块中使用,代码例例如下:
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Currrent {
//用于操作的对象 monitor 锁
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
Wait thread1 = new Wait("wait1");
Wait thread2 = new Wait("wait2");
Wait thread3 = new Wait("wait3");
Notify notify = new Notify("notify");
//三个线程开始进入wait()
thread1.start();
thread2.start();
thread3.start();
Thread.sleep(1000);
//唤醒线程进行notify()
notify.start();
}
static class Wait extends Thread{
private String name;
public Wait(String name) {
this.name=name;
}
@Override
public void run() {
synchronized (object) {
try {
System.out.println("线程"+this.name+"进入");
//当前线程进入等待队列
object.wait(10000);
System.out.println("线程"+this.name+"结束wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+this.name+"完成");
}
}
}
static class Notify extends Thread{
private String name;
public Notify(String name) {
this.name=name;
}
@Override
public void run() {
synchronized (object) {
//所有在对象object等待队列中的线程进入阻塞度列
object.notify();
System.out.println("线程"+this.name+"调用了object.notify()");
System.out.println("线程"+this.name+"释放了锁");
//此线程释放了object对象的锁,等待队列中的某个线程将会获取并继续执行wait()方法之后的代码
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+this.name+"锁外内容");
}
}
}
网友评论