思路:开启两个线程,线程t1添加元素,线程t2监控元素个数为5。如何保证元素个数为5的时候t2执行,这里就思考如何再元素个数为5的时候t2拿到锁执行,t1等待。直到t2执行完之后t1再拿到锁。
第一种方法:
public class waitFiveSecondTest { volatile List list = new ArrayList<>(); public void add(Object o){ list.add(o); } public int size(){ return list.size(); } public static void main(String[] args) { waitFiveSecondTest w = new waitFiveSecondTest(); final Object lock = new Object(); new Thread(()->{ System.out.println("t2启动鸟"); synchronized (lock){ if(w.size()!=5){ try { lock.wait(); //1、t2先执行,元素个数还没有到5的时候wait()等待,释放锁给t1。 //2、直到t1wait()释放了锁之后,t2重新拿到锁执行 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2执行结束鸟"); lock.notify(); //3、t2执行完了之后,需要唤醒t1,直到t2执行完之后锁释放。t1拿到继续添加元素 } },"t2").start(); new Thread(()->{ synchronized (lock){ System.out.println("t1启动鸟"); //t1拿到锁了开始启动执行添加元素 for (int i = 0; i <10 ; i++) { w.add(new Object()); System.out.println("add"+i); if(w.size()==5){ //t1往容器里面添加元素到5的时候 lock.notify(); //notify唤醒t2.但是notify不会释放锁,所以t2还不能执行 try { lock.wait(); //那么需要让t1释放锁,让t2拿到。直到t2执行完,并唤醒t1,t1继续执行 } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("t1执行结束鸟"); } },"t1").start(); } }
方法一程序略微复杂。其实就是使用了wait和notyfy方法来控制锁。这里首先要理解wait()是释放了锁的,但是notyfy()没有释放锁。所以需要注意。
接着看下方法二:对于方法1的优化,方法1之所以复杂就是因为控制锁的时候需要两个线程协调锁。所以要程序更简单使用一个控制锁的flag就好,这里使用门栓CountDownLatch。CountDownLatch中值1-->0的时候们拴就开了,countDown()方法开拴。仍然是上面的思路,t2等待,t1添加元素到5给t2执行。
public class waitFiveSecondTest { volatile List list = new ArrayList<>(); public void add(Object o){ list.add(o); } public int size(){ return list.size(); } public static void main(String[] args) { waitFiveSecondTest w = new waitFiveSecondTest(); CountDownLatch latch= new CountDownLatch(1); new Thread(()->{ System.out.println("t2启动鸟"); if(w.size()!=5){ try { latch.await(); //等着开门,await不需要锁定任何对象。 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2执行结束鸟"); },"t2").start(); new Thread(()->{ System.out.println("t1启动鸟"); for (int i = 0; i <10 ; i++) { w.add(new Object()); System.out.println("add"+i); if(w.size()==5){ latch.countDown(); } } System.out.println("t1执行结束鸟"); },"t1").start(); } }