线程之间通信1

使用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 添加了一个元素..

 

猜你喜欢

转载自xdx2599.iteye.com/blog/2306879