1、案例一
/** * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数, * 当个数到5个时,线程2给出提示并结束线程2 * * 这里list在两个线程之间不保证可见性,所以线程2始终结束不了 */ @Slf4j(topic = "test") public class Container1 { List lists = new ArrayList(); public void add(Object o){ lists.add(o); } public int size(){ return lists.size(); } public static void main(String[] args) { Container1 c = new Container1(); new Thread(()->{ for (int i = 0; i < 10; i++) { c.add(new Object()); log.debug("add " + i); try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }," t1").start(); new Thread(()->{ while (true) { if (c.size() == 5) { break; } } log.debug("t2线程结束"); }, "t2").start(); } }
2、案例二
/** * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数, * 当个数到5个时,线程2给出提示并结束 * * 有两个问题,第一由于没有加同步,可能size等于5的时候,有另外一个线程加了一下才break,不是很精确 * 第二个问题就是浪费cpu,T2线程用的是死循环 */ @Slf4j(topic = "test") public class Container2 { 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) { Container2 c = new Container2(); new Thread(()->{ for (int i = 0; i < 10; i++) { c.add(new Object()); log.debug("add " + i); try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }," t1").start(); /** * 浪费性能 * 当条件不满足的我应该放弃CPU 阻塞 * 当条件满足的时候才执行 wait notify */ new Thread(()->{ while (true) { if (c.size() == 5) { break; } } log.debug("t2线程结束"); }, "t2").start(); } }
3、案例三
** * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时, * 线程2给出提示并结束 * * 这里虽然T2能够及时收到消息唤醒,但是wait会释放锁,notify不会释放锁,所以T1线程结束后 * T2线程才执行完成 */ @Slf4j(topic = "test") public class Container3 { 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) { Container3 c = new Container3(); Object lock = new Object(); new Thread(()->{ synchronized (lock) { log.debug("t2启动"); if (c.size() != 5) { try { lock.wait(); } catch (Exception e) { e.printStackTrace(); } } log.debug("t2结束"); } }," t2").start(); new Thread(()->{ log.debug("t1启动"); synchronized (lock) { for (int i = 0; i < 10; i++) { c.add(new Object()); log.debug("add " + i); if (c.size() == 5) { lock.notify(); } try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } }, "t1").start(); } }
4、案例四
/** * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数, * 当个数到5个时,线程2给出提示并结束 * * 相比较上一个例子,这里T1里面用wait释放锁,T2能够及时结束 */ @Slf4j(topic = "test") public class Container4 { 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) { Container4 c = new Container4(); Object lock = new Object(); new Thread(()->{ synchronized (lock) { log.debug("t2启动"); if (c.size() != 5) { try { lock.wait(); } catch (Exception e) { e.printStackTrace(); } } log.debug("t2结束"); lock.notify(); } }," t2").start(); new Thread(()->{ log.debug("t1启动"); synchronized (lock) { for (int i = 0; i < 10; i++) { c.add(new Object()); log.debug("add " + i); if (c.size() == 5) { lock.notify(); try { lock.wait();//要释放锁,T2才能得到锁得以执行 } catch (Exception e) { e.printStackTrace(); } } try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } } }, "t1").start(); } }
5、案例五
/** * 一道面试题:实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数, * 当个数到5个时,线程2给出提示并结束 * * CountDownLatch * 使用await和countdown方法替代wait和notify * CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行 * 相当于是发令枪,运动员线程调用await等待,计数到0开始运行 * 当不涉及同步,只是涉及线程通信的时候,用synchronized加wait,notify就显得太重了 */ @Slf4j(topic = "test") public class Container5 { 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) { Container5 c = new Container5(); CountDownLatch latch = new CountDownLatch(1); String s = new String("XXXXX"); new Thread(()->{ log.debug("t2启动"); if (c.size() != 5) { try { //阻塞 latch.await();//准备 } catch (Exception e) { e.printStackTrace(); } log.debug("t2结束"); } }," t2").start(); new Thread(()->{ log.debug("t1启动"); for (int i = 0; i < 10; i++) { c.add(new Object()); log.debug("add " + i); if (c.size() == 5) { latch.countDown(); } try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }, "t1").start(); } }