使用wait/notify 方法实现线程之间的通信 这两个方法都是object类的方法
换句话说 java为所有的对象都提供了这两个方法
1 wait 和notify 必须配合synchronized 关键字来使用
2 wait 方法释放锁,notify方法不释放锁
public class Test2 {
private volatile static List list = new ArrayList();
@SuppressWarnings("unchecked")
public void add(){
list.add("aaa");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final Test2 test2 = new Test2();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
test2.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 (list.size()==5) {
System.out.println("当前线程收到通知:"+Thread.currentThread().getName()+" list size = 5 线程停止.. ");
throw new RuntimeException();
}
}
}
},"t2");
t1.start();
t2.start();
}
}
上面一段代码的 意图是当线程t1 执行到add操作 当list.size()==5时 发出通知
通知 t2 线程结束退出
执行结果如下:
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread "t2" java.lang.RuntimeException
at test.Test2$2.run(Test2.java:59)
at java.lang.Thread.run(Unknown Source)
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
使用 wait / notify 来改写后的代码如下
package test;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("rawtypes")
public class Test2 {
private volatile static List list = new ArrayList();
@SuppressWarnings("unchecked")
public void add(){
list.add("aaa");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final Test2 test2 = new Test2();
final Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
test2.add();
System.out.println("当前线程:"+Thread.currentThread().getName()+" 添加了一个元素..");
if (list.size()==5) {
lock.notify();
System.out.println(" 发出通知..");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println(" in t2");
if (list.size()!=5) {
try {
System.out.println(" t2 start to wait ");
lock.wait();
System.out.println(" t2 end wait ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程收到通知:"+Thread.currentThread().getName()+" list size = 5 线程停止.. ");
throw new RuntimeException();
}
}
},"t2");
t2.start();
t1.start();
}
}
执行结果如下:
in t2
t2 start to wait
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
发出通知..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
t2 end wait
当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread "t2" java.lang.RuntimeException
at test.Test2$2.run(Test2.java:62)
at java.lang.Thread.run(Unknown Source)
事实上并没有如预期中那样 在 list size = 5 线程停止..
分析原因如下:
代码执行顺序如下
首先 t2 获得 lock 然后 执行lock.wait()释放lock 并等待 notify
然后 t1 获得 lock 执行add操作 当list.size() ==5 的时候 执行lock.notify() 此时 t1并没有释放 lock 而是执行完整个操作的时候才去释放lock 此时 t2 重新获得lock 继续执行下面的操作
这样显示没有达到我们的目的 没有及时的通知到线程t2
其实如果利用concurrent包里的countDownLatch可以用极为简单的代码来实现我们的目的
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@SuppressWarnings("rawtypes")
public class Test2 {
private volatile static List list = new ArrayList();
@SuppressWarnings("unchecked")
public void add(){
list.add("aaa");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final Test2 test2 = new Test2();
final CountDownLatch countDownLatch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
test2.add();
System.out.println("当前线程:"+Thread.currentThread().getName()+" 添加了一个元素..");
if (list.size()==5) {
System.out.println(" 发出通知..");
countDownLatch.countDown();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(" in t2");
if (list.size()!=5) {
try {
System.out.println(" t2 start to wait ");
countDownLatch.await();
System.out.println(" t2 end wait ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程收到通知:"+Thread.currentThread().getName()+" list size = 5 线程停止.. ");
throw new RuntimeException();
}
},"t2");
t2.start();
t1.start();
}
}
执行结果如下
in t2
t2 start to wait
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
发出通知..
t2 end wait
当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread "t2" java.lang.RuntimeException
at test.Test2$2.run(Test2.java:59)
at java.lang.Thread.run(Unknown Source)
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..
当前线程:t1 添加了一个元素..