一道面试题:实现一个容器,提供两个方法,add,size,写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束线程2
第一种,使用wait()和notify()来实现
public class test { volatile List lists = new ArrayList();
public void add(Object o){ lists.add(o); }
public int size(){ return lists.size(); }
public static void main(String[] args) { test c = new test(); Object lock = new Object(); new Thread(()->{ synchronized (lock) { System.out.println("t2启动"); if (c.size() != 5) { try { lock.wait();//释放锁 } catch (Exception e) { e.printStackTrace(); } } System.out.println("t2结束"); lock.notify(); } }," t2").start(); new Thread(()->{ System.out.println("t1启动"); synchronized (lock) { for (int i = 0; i < 10; i++) { c.add(new Object()); System.out.println("add " + i); if (c.size() == 5) { lock.notify();//唤醒当前等待线程,但是不会释放当前线程持有的锁,所以T2线程无法获得锁,依然无法执行 try { lock.wait();//释放锁,T2才能得到锁得以执行 } catch (Exception e) { e.printStackTrace(); } } try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } }, "t1").start();
}
}
第二种方法,可以使用CountDownLatch来进行控制
public class test {
volatile List lists = new ArrayList();
public void add(Object o){ lists.add(o); }
public int size(){ return lists.size(); }
public static void main(String[] args) { test c = new test();
CountDownLatch latch = new CountDownLatch(5);
new Thread(()->{ System.out.println("t2启动"); if (c.size() != 5) { try { latch.await();//准备 } catch (Exception e) { e.printStackTrace(); } System.out.println("t2结束"); } }," t2").start();
new Thread(()->{ System.out.println("t1启动"); for (int i = 0; i < 10; i++) { c.add(new Object()); System.out.println("add " + i); if (c.size() == 5) { latch.countDown();//减一操作 } try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }, "t1").start(); }
}
CountDownLatch 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了