题目:实现一个容器,提供两个方法,add,size。写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束。

程序一,分析下面程序能否实现

List lists = new ArrayList();public void add(Object o) {lists.add(o);}public int size() {return lists.size();}public static void main(String[] args) {MyContainer1 c = new MyContainer1();new Thread(() -> { //线程一for (int i = 0; i < 10; i++) {c.add(new Object());System.out.println("add" + i);try {TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();}}}, " t1").start();new Thread(() -> { //线程二while (true) {if (c.size() == 5) {break;}}System.out.println("t2线程结束");}, "t2").start();}

运行结果:线程1运行完成,正常打印。线程2一直在运行,未结束。
分析:lists对于线程2不可见,所以不能实时的访问到lists的size。

程序二 加volatile关键字

//添加volatile,使t2能够得到通知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) {MyContainer2 c = new MyContainer2();new Thread(()->{ //线程一for (int i = 0; i < 10; i++) {c.add(new Object());System.out.println("add " + i);try {TimeUnit.MILLISECONDS.sleep(10);} catch (Exception e) {e.printStackTrace();}}}," t1").start();new Thread(()->{ //线程二while (true) {if (c.size() == 5) {break;}}System.out.println("t2线程结束");}, "t2").start();}

运行结果:正常
分析:由于volatile关键字保证了lists对于线程2可见,所以当size发生变化后线程2能获取到lists的size值。
不足:线程2的死循环非常浪费cpu资源。

程序三 使用wait和notify实现

    //添加volatile,使t2能够得到通知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) {MyContainer4 c = new MyContainer4();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();} catch (Exception e) {e.printStackTrace();}}try {TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();}}}}, "t1").start();}

这里使用wait和notify做到,wait会释放锁,而notify不会释放锁。需要注意的是运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以。

程序四 使用Latch(门闩)替代wait notify来进行通知

    //添加volatile,使t2能够得到通知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) {MyContainer5 c = new MyContainer5();Object lock = new Object();CountDownLatch latch = new CountDownLatch(1);new Thread(() -> { //线程一System.out.println("t2启动");if (c.size() != 5) {try {latch.await();// 也可以指定等待时间]//latch.await(5000, TimeUnit.MICROSECONDS);} 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) {// 打开门阀,让t2得以执行latch.countDown();}try {TimeUnit.SECONDS.sleep(1);} catch (Exception e) {e.printStackTrace();}}}, "t1").start();}

使用Latch(门闩)替代wait notify来进行通知 好处是通信方式简单,同时也可以指定等待时间 使用await和countdown方法替代wait和notify。
CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行。 当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify就显得太重了。这时应该考虑countdownlatch/cyclicbarrier/semaphore
读下面文章进行深入了解:
Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

高并发编程之面试题一相关推荐

  1. 高并发编程_高并发编程系列:7大并发容器详解(附面试题和企业编程指南)...

    不知道从什么时候起,在Java编程中,经常听到Java集合类,同步容器.并发容器,高并发编程成为当下程序员需要去了解掌握的技术之一,那么他们有哪些具体分类,以及各自之间的区别和优劣呢? 只有把这些梳理 ...

  2. Java并发编程面试题(2020最新版)

    转载自  Java并发编程面试题(2020最新版) 基础知识 并发编程的优缺点 为什么要使用并发编程(并发编程的优点) 充分利用多核CPU的计算能力:通过并发编程的形式可以将多核CPU的计算能力发挥到 ...

  3. libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  4. java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单!

    点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书! ​ 在介绍本书单之前,我想先问一下各位读者,你们之前对于Java并发编程的了解有多少呢.经过了1 ...

  5. 【2022最新Java面试宝典】—— Java并发编程面试题(123道含答案)

    目录 一.基础知识 1. 为什么要使用并发编程 2. 多线程应用场景 3. 并发编程有什么缺点 4. 并发编程三个必要因素是什么? 5. Java 程序中怎么保证多线程的运行安全? 6. 并行和并发有 ...

  6. 网络编程和并发编程面试题

    网络编程和并发编程面试题 1.简述 OSI 七层协议. 一.应用层 与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的.例如,一个没有通信功能的字处理程序就不能执行通信的代码,从事字处理工作 ...

  7. Java JUC高并发编程(一)

    目录 一.概述 二.Lock接口 三.线程间的通信 解决虚假唤醒问题 Lock通信示例: 四.线程间定制化通信 一.概述 JUC就是java.util.concurrent工具包的简称,这是一个处理线 ...

  8. 啃完阿里这份高并发编程核心笔记,反手涨了 5K

    高并发编程 提到并发编程很多人就会头疼了:首先就是一些基础概念:并发,并行,同步,异步,临界区,阻塞,非阻塞还有各种锁全都砸你脸上,随之而来的就是要保证程序运行时关键数据在多线程中的可见性.核心业务的 ...

  9. 啃完阿里这份高并发编程核心笔记,反手涨了5K

    高并发编程 提到并发编程很多人就会头疼了:首先就是一些基础概念:并发,并行,同步,异步,临界区,阻塞,非阻塞还有各种锁全都砸你脸上,随之而来的就是要保证程序运行时关键数据在多线程中的可见性.核心业务的 ...

  10. 高并发编程-重新认识Java内存模型(JMM)

    文章目录 从CPU到内存模型 内存模型如何确保缓存一致性 并发变成需要解决的问题 (原子性.可见性.有序性) 内存模型需要解决的问题 Java内存模型 JMM的API实现 原子性 synchroniz ...

最新文章

  1. vim ctags使用方法
  2. 每天一个前端名词——Babel
  3. modify timezone
  4. MFC 直线 虚线 折线 圆 椭圆 矩形 弧形
  5. Android之jni编译报错comparsion between signed and unsigned integer expressions解决办法
  6. 视频光端机选型及常见品牌
  7. 支付宝兑换的扫地机器人_支付宝里这笔钱赶紧用掉!年底过期作废
  8. dubbo发布webservice服务
  9. vb使用open方法读写文件
  10. zip4j实现文件压缩与解压缩 common-compress压缩与解压缩
  11. paip.android 手机输入法制造大法
  12. (首个填坑)联想拯救者Y7000(自带win10 home) 安装Ubuntu16.04.6 + NVIDIA GTX1650驱动
  13. mysql英文版怎么调中文_navicat for mysql怎么设置中文
  14. 官方固件库V1.4版本介绍
  15. NoSQL--Redis
  16. Python ---------列表 集合 字典 深浅拷贝
  17. 微信多客服系统开发教程
  18. Hexo博客搭建教程
  19. python定时导出已发送文件_Python链接数据库查询导出查询结果到Excel并定时发送邮件到指定邮箱,实现巡检功能(亲测可用!!!)...
  20. CrossWalk - Android 动态加载so库文件

热门文章

  1. CSS世界Bug般的存在——字母x与“居中”
  2. 布客·ApacheCN 翻译校对活动进度公告 2020.5
  3. Java基础语法总结
  4. 读取AutoCAD中的样条曲线(一)
  5. 使用Zoiper与freeSWITCH开视频会议
  6. VsCode之在vue中HTML代码使用自动补全插件
  7. API多帐户跨平台MT4跟单系统如何选择服务器?
  8. matlab编译桁架有限元计算(附有完整代码)
  9. 腾讯地图获取全国行政区划检索列表Demo
  10. SQL中 decode()函数的应用和一些特殊的传值方法