Object类提供了一套等待/通知的API,它是由以下3个方法组成。
wiat():导致当前线程一直处于等待状态,直到另外的线程盗用这个线程的notify()或者 notifyAll()方法,或者等其他的线程中断当前等待的线程。
notify():唤醒正在等待改对象监视器的单条线程。如果有几个线程在该对象锁上,则其中的某一条会被挑选出来唤醒,这种选择是随意的。
notifyAll():唤醒正在等待该对象监视器的全部线程(除非当前线程已经释放了该对象上的锁)。
还有下面重要的两点:
- wiat方法会释放锁,而notify方法不会释放锁
- wiat和notify方法都必须配合synchronized关键字使用
一道java面试题,将下面代码进行优化
private volatile static List list = new ArrayList();
public void add(){
list.add("bjsxt");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd1 list1 = new ListAdd1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i <10; i++){
list1.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
if(list1.size() == 5){
System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");
throw new RuntimeException();
}
}
}
}, "t2");
t1.start();
t2.start();
}
使用wait()和notify()方法进行通讯
public volatile static ArrayList list = new ArrayList(20);
public void add(){
list.add("数据+1");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd1Test list1 = new ListAdd1Test();
final Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock){
for (int i = 0; i <10 ; i++) {
list1.add();
System.out.println("数据大小---"+list1.size());
if(i==5){
lock.notify();
}
}
}
} );
Thread t2 = new Thread(() -> {
synchronized (lock){
try {
//此处如果不指定的话 lock会一直wait下去,因为
lock.wait();
System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");
throw new RuntimeException();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} );
t2.start();
t1.start();
}
使用上述wait和notify方法虽然可以到达目的,但是也有一个致命的问题就是notify方法并不会释放锁,必须等到
代码执行完,释放了lock锁,t2线程才能拿到lock锁。及不能够实时的去进行通信。另一种方式使用juc下面的CountDownLatch更为明智和优雅.
private volatile static List list = new ArrayList();
public void add(){
list.add("bjsxt");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd2 list2 = new ListAdd2();
// 1 实例化出来一个 lock
// 当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用
//final Object lock = new Object();
final CountDownLatch countDownLatch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
//synchronized (lock) {
for(int i = 0; i <10; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
if(list2.size() == 5){
System.out.println("已经发出通知..");
countDownLatch.countDown();
//lock.notify();
}
}
//}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//synchronized (lock) {
if(list2.size() != 5){
try {
//System.out.println("t2进入...");
//lock.wait();
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
//}
}
}, "t2");
t2.start();
t1.start();
}