文章目录

  • 为什么要用到并发
  • 并发编程有哪些缺点
    • 频繁的上下文切换
    • 线程安全

为什么要用到并发

在多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升。

顶级计算机科学家Donald Ervin Knuth如此评价这种情况:在我看来,这种现象(并发)或多或少是由于硬件设计者无计可施了导致的,他们将摩尔定律的责任推给了软件开发者。

另外,在特殊的业务场景下先天的就适合于并发编程。比如在图像处理领域,一张1024X768像素的图片,包含达到78万6千多个像素。即时将所有的像素遍历一边都需要很长的时间,面对如此复杂的计算量就需要充分利用多核的计算的能力。又比如当我们在网上购物时,为了提升响应速度,需要拆分,减库存,生成订单等等这些操作,就可以进行拆分利用多线程的技术完成。面对复杂业务模型,并行程序会比串行程序更适应业务需求,而并发编程更能吻合这种业务拆分 。

正是因为这些优点,使得多线程技术能够得到重视,也是一名CS学习者应该掌握的:

  • 充分利用多核CPU的计算能力
  • 方便进行业务拆分,提升应用性能

并发编程有哪些缺点

多线程技术有这么多的好处,难道就没有一点缺点么,就在任何场景下就一定适用么?很显然不是。

频繁的上下文切换

时间片是CPU分配给各个线程的时间,因为时间非常短,所以CPU不断通过切换线程,让我们觉得多个线程是同时执行的,时间片一般是几十毫秒。而每次切换时,需要保存当前的状态起来,以便能够进行恢复先前状态,而这个切换时非常损耗性能,过于频繁反而无法发挥出多线程编程的优势

通常减少上下文切换可以采用无锁并发编程,CAS算法,使用最少的线程和使用协程。

  • 无锁并发编程:可以参照concurrentHashMap锁分段的思想,不同的线程处理不同段的数据,这样在多线程竞争的条件下,可以减少上下文切换的时间。
  • CAS算法,利用Atomic下使用CAS算法来更新数据,使用了乐观锁,可以有效的减少一部分不必要的锁竞争带来的上下文切换
  • 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多的线程,这样会造成大量的线程都处于等待状态
  • 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

由于上下文切换也是个相对比较耗时的操作,所以在”java并发编程的艺术”一书中有过一个实验,并发累加未必会比串行累加速度要快。

线程安全

多线程编程中最难以把握的就是临界区线程安全问题,稍微不注意就会出现死锁的情况,一旦产生死锁就会造成系统功能不可用。

public class DeadLockDemo {private static String resource_a = "A";private static String resource_b = "B";public static void main(String[] args) {deadLock();}public static void deadLock() {Thread threadA = new Thread(new Runnable() {@Overridepublic void run() {synchronized (resource_a) {System.out.println("get resource a");try {Thread.sleep(3000);synchronized (resource_b) {System.out.println("get resource b");}} catch (InterruptedException e) {e.printStackTrace();}}}});Thread threadB = new Thread(new Runnable() {@Overridepublic void run() {synchronized (resource_b) {System.out.println("get resource b");synchronized (resource_a) {System.out.println("get resource a");}}}});threadA.start();threadB.start();}
}

在上面的这个demo中,开启了两个线程threadA, threadB,其中threadA占用了resource_a, 并等待被threadB释放的resource _b。threadB占用了resource _b正在等待被threadA释放的resource _a。因此threadA,threadB出现线程安全的问题,形成死锁。同样可以通过jps,jstack证明这种推论:

"Thread-1":waiting to lock monitor 0x000000000b695360 (object 0x00000007d5ff53a8, a java.lang.String),which is held by "Thread-0"
"Thread-0":waiting to lock monitor 0x000000000b697c10 (object 0x00000007d5ff53d8, a java.lang.String),which is held by "Thread-1"Java stack information for the threads listed above:
===================================================
"Thread-1":at learn.DeadLockDemo$2.run(DeadLockDemo.java:34)- waiting to lock <0x00000007d5ff53a8(a java.lang.String)- locked <0x00000007d5ff53d8(a java.lang.String)at java.lang.Thread.run(Thread.java:722)
"Thread-0":at learn.DeadLockDemo$1.run(DeadLockDemo.java:20)- waiting to lock <0x00000007d5ff53d8(a java.lang.String)- locked <0x00000007d5ff53a8(a java.lang.String)at java.lang.Thread.run(Thread.java:722)Found 1 deadlock.

如上所述,完全可以看出当前死锁的情况。

那么,通常可以用如下方式避免死锁的情况:

  • 避免一个线程同时获得多个锁;
  • 避免一个线程在锁内部占有多个资源,尽量保证每个锁只占用一个资源;
  • 尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时当前线程不会阻塞;
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况

所以,如何正确的使用多线程编程技术有很大的学问,比如如何保证线程安全,如何正确理解由于JMM内存模型在原子性,有序性,可见性带来的问题,比如数据脏读,DCL等这些问题(在后续篇幅会讲述)。而在学习多线程编程技术的过程中也会让你收获颇丰。

Java并发编程实战——并发编程的优缺点相关推荐

  1. Java并发编程实战~并发容器

    在容器领域一个容易被忽视的"坑"是用迭代器遍历容器,例如在下面的代码中,通过迭代器遍历容器 list,对每个元素调用 foo() 方法,这就存在并发问题,这些组合的操作不具备原子性 ...

  2. Java并发编程实战————并发技巧小结

    可变状态是至关重要的.所有的并发问题都可以归结为如何协调对并发状态的访问.可变状态越少,就越容易确保线程安全性. 尽量将域声明为final类型,除非需要它们是可变的. 不可变对象一定是线程安全的.不可 ...

  3. 视频教程-Java并发编程实战-Java

    Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...

  4. Java 7并发编程实战手册

    2019独角兽企业重金招聘Python工程师标准>>> Java 7并发编程实战手册 本书是 Java 7 并发编程的实战指南,介绍了Java 7 并发API 中大部分重要而有用的机 ...

  5. java 高并发第三阶段实战_JAVA多线程编程实战视频-第三阶段(共80节)

    高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍 高并发编程第三阶段03讲 利用CAS构造 ...

  6. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  7. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  8. aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  9. java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...

    [Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...

  10. c++并发编程实战_Java 并发编程实战:JAVA中断线程几种基本方法

    一个多线程Java程序,只有当其全部线程执行结束时(更具体地说,是所有非守护线程结束或者某个线程调用system.exit()方法的时候) ,才会结束运行.有时,为了终止程序或者取消一个线程对象所执行 ...

最新文章

  1. 反模式? 只有模式不彻底吧
  2. layui图片src 指定后没显示_2种方法用python调用cv2模块给图片打马赛克
  3. Android Bitmap开发之旅--基本操作
  4. 哈夫曼编码原理与Python实现代码(附手动推导过程原稿真迹)
  5. 极酷WIFI深度剖析免费WIFI
  6. 编译器错误不能找到元数据文件
  7. SVN 小乌龟(TortoiseSVN)本地文件更新报错Another process is blocking the working copy database 解决方法
  8. html ur是什么意思_url是什么意思?
  9. 好用的空气质量查询API
  10. java-喝饮料换空瓶问题
  11. 数据湖和数据仓库区别介绍
  12. thinkpad 重装--AHCI 导致系统蓝屏---迅盘
  13. 中国有句俗语叫“三天打鱼两天晒网”。某人从2010年1月1日起开始“三天打鱼两天晒网”, 问这个人在以后的某一天中是“打鱼”还是“晒网”。用C或C++语言/java/python实现程序解决问题
  14. matlab直流调速系统设计,直流调速系统的matlab设计与仿真系统设计
  15. python文件用pyinstaller库进行打包时,代码中用到的图片和我们自定义的python package包的处理办法
  16. 亚信科技Java后端实习
  17. matlab绘图(其他形式的二维曲线)
  18. H5 移动端 钉钉微应用 调用微信内置地图
  19. 【课程汇总】OpenHarmony全场景Demo数字管家系列课(附链接)
  20. windows常见问题汇集

热门文章

  1. HEX文件和BIN文件格式的区别
  2. 将bin文件以16进制字符显示
  3. Mysql数据库优化方案
  4. IP地址的分类,五分类编制CIDR以及子网的划分和子网掩码
  5. SQL Server从入门到精通pdf
  6. c语言源程序是系统,c语言管理系统源代码_图书管理系统c语言程序设计
  7. mysql的主从同步查询_mysql主从同步
  8. Linux上安装gcc
  9. 《Java练习题》Java编程题合集(转载)
  10. 彩虹查课插件 使用说明 网课查询插件 极速版