第一次写,错的地方,希望大家指出,谢谢!
wait ,notify都是Object中的方法:
1 ,他们必须配合synchronized关键字使用
2,wait方法释放锁,notify方法不释放锁
需求: 一个集合,2个线程,一个线程往集合中添加10个元素,另一个线程判断,如果集合中正好为5个元素时,就执行某段代码;
1 public class ListAdd2 { 2 3 private static List list = new ArrayList(); 4 public void add() { 5 list.add("hello world"); 6 } 7 8 public int size() { 9 return list.size(); 10 } 11 12 13 public static void main(String[] args) { 14 15 ListAdd2 listAdd = new ListAdd2(); 16 17 // 这边定义一个锁 18 final Object lock = new Object(); 19 20 Thread t1 = new Thread(new Runnable() { 21 @Override 22 public void run() { 23 synchronized (lock) { 24 System.out.println("t1启动"); 25 for (int i = 0; i < 10; i++) { 26 try { 27 listAdd.add(); 28 System.out.println("当前线程:" 29 + Thread.currentThread().getName() 30 + "添加了一个元素.."); 31 Thread.sleep(500); 32 if (listAdd.size() == 5) { 33 System.out.println("t1发出通知"); 34 lock.notify(); // 锁进行通知 不释放锁 35 } 36 } 37 catch (InterruptedException e) { 38 e.printStackTrace(); 39 } 40 } 41 } 42 } 43 }); 44 45 Thread t2 = new Thread(new Runnable() { 46 47 @Override 48 public void run() { 49 50 synchronized (lock) { 51 System.out.println("t2启动"); 52 if (listAdd.size() != 5) { 53 try { 54 lock.wait(); // 不等于 5 线程2 就在这里等待 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } 58 } 59 System.out.println("当前线程:" 60 + Thread.currentThread().getName() + "收到通知线程停止.."); 61 throw new RuntimeException(); 62 } 63 } 64 }); 65 t2.start(); 66 t1.start(); 67 } 68 }
打印结果如下:
t2启动
t1启动
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
t1发出通知
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-1收到通知线程停止..
Exception in thread "Thread-1" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd2$2.run(ListAdd2.java:66)
at java.lang.Thread.run(Thread.java:748)
首先线程2先启动执行,获取了lock锁,在wait()方法,进行等待,并释放锁。
线程1 获取了lock锁,添加了5个元素后,发出了通知,唤醒锁,但是此时线程1 并没有释放锁,而是继续执行,等循环结束后,释放锁
线程2 继续运行,执行 后面的业务逻辑。
这里并不能满足我们的业务需求,我们希望集合中元素一旦有5个时,就执行线程2,而不是等到线程1全部执行完,才执行线程2;
所以这里我们要使用java.util.concurrent 包中的类 CountDownLatch
public static void main(String[] args) { ListAdd2 listAdd = new ListAdd2(); // 这边定义一个锁 // final Object lock = new Object(); CountDownLatch countDownLatch = new CountDownLatch(1); // 这里的 1 代表计数器为1 Thread t1 = new Thread(new Runnable() { @Override public void run() { // synchronized (lock) { System.out.println("t1启动"); for (int i = 0; i < 10; i++) { try { listAdd.add(); System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素.."); Thread.sleep(500); if (listAdd.size() == 5) { System.out.println("t1发出通知"); countDownLatch.countDown(); // 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 // lock.notify(); // 锁进行通知 不释放锁 } } catch (InterruptedException e) { e.printStackTrace(); } } } // } }); // 启动线程1 Thread t2 = new Thread(new Runnable() { @Override public void run() { // synchronized (lock) { System.out.println("t2启动"); if (listAdd.size() != 5) { try { countDownLatch.await(); // 线程等待 // lock.wait(); // 不等于 5 线程2 就在这里等待 } catch (Exception e) { e.printStackTrace(); } } System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止.."); throw new RuntimeException(); } // } }); t2.start(); t1.start(); }
打印结果: 当集合中元素为5时,执行countDownLatch.countDown(); 释放所有等待的线程,线程2就立刻执行了。
如果CountDownLatch countDownLatch = new CountDownLatch(2); //设置为2,则要执行2次,countDownLatch.countDown(),也就是将当计数器为0时,释放所有等待的线程
t2启动
t1启动
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
t1发出通知
当前线程:Thread-0添加了一个元素..
当前线程:Thread-1收到通知线程停止..
Exception in thread "Thread-1" java.lang.RuntimeException
at com.bjsxt.base.conn008.ListAdd2$2.run(ListAdd2.java:69)
at java.lang.Thread.run(Thread.java:748)
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..
当前线程:Thread-0添加了一个元素..