- wait会释放锁,而notify不会释放锁。
- wait()和notify()是object类的方法,这两个方法必须在synchronized代码块或synchronized修饰的方法中使用,调用这两个方法的代码块必须要获得synchronized。
实现一个容器,提供两个方法,add,size写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class T03_NotifyHoldingLock { //wait notify
//添加volatile,使t2能够得到通知
volatile List lists = new ArrayList();
public void add(Object o) {
lists.add(o);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
T03_NotifyHoldingLock c = new T03_NotifyHoldingLock();
final Object lock = new Object();
new Thread(() -> {
synchronized(lock) {
System.out.println("t2启动");
if(c.size() != 5) {
try {
lock.wait();//t2释放锁进入等待队列等待别的线程调用notify唤醒进入等待队列再被cpu分配执行机会才会继续向下执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2 结束");
lock.notify();
}
}, "t2").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
new Thread(() -> {
System.out.println("t1启动");
synchronized(lock) {
for(int i=0; i<10; i++) {
c.add(new Object());
System.out.println("add " + i);
if(c.size() == 5) {
lock.notify();//不释放锁 只唤醒调用wait();方法的线程t2让他进入等待队列还是要等到t1执行完毕释放锁,
// T2获取锁之后才会从调用lock.wait();的位置继续向下执行
try {
lock.wait();//t2释放锁进入等待队列等待别的线程调用notify唤醒进入等待队列再被cpu分配执行机会才会继续向下执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t1").start();
}
}
//关键之处在于 add了size到5之后暂停,别的线程能获取运行机会 并监控到等于5然后继续运行
关键之处在于是t1线程在add的时候,当size等于5了,要能够让t2线程知道size等于5,所以加上了volatile关键字在list保证线程可见性在T1和T2线程。
第二个就是当size等于5的时候能让T1阻塞,让T2立刻去执行wait后面的代码,所以T1调notify只是让T2有机会运行,但是T1不释放锁,T2还是不会运行,所以T1又调用wait释放锁,让T2运行Wait方法之后的。T2运行完结束之前调用notify唤醒T1让其继续运行,如果不调用notify,T1会一直处于wait状态,不会获取到运行机会。



