Java并发编程实战——并发编程的优缺点
文章目录
- 为什么要用到并发
- 并发编程有哪些缺点
- 频繁的上下文切换
- 线程安全
为什么要用到并发
在多核的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并发编程实战——并发编程的优缺点相关推荐
- Java并发编程实战~并发容器
在容器领域一个容易被忽视的"坑"是用迭代器遍历容器,例如在下面的代码中,通过迭代器遍历容器 list,对每个元素调用 foo() 方法,这就存在并发问题,这些组合的操作不具备原子性 ...
- Java并发编程实战————并发技巧小结
可变状态是至关重要的.所有的并发问题都可以归结为如何协调对并发状态的访问.可变状态越少,就越容易确保线程安全性. 尽量将域声明为final类型,除非需要它们是可变的. 不可变对象一定是线程安全的.不可 ...
- 视频教程-Java并发编程实战-Java
Java并发编程实战 2018年以超过十倍的年业绩增长速度,从中高端IT技术在线教育行业中脱颖而出,成为在线教育领域一匹令人瞩目的黑马.咕泡学院以教学培养.职业规划为核心,旨在帮助学员提升技术技能,加 ...
- Java 7并发编程实战手册
2019独角兽企业重金招聘Python工程师标准>>> Java 7并发编程实战手册 本书是 Java 7 并发编程的实战指南,介绍了Java 7 并发API 中大部分重要而有用的机 ...
- java 高并发第三阶段实战_JAVA多线程编程实战视频-第三阶段(共80节)
高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍 高并发编程第三阶段03讲 利用CAS构造 ...
- Java并发编程实战笔记2:对象的组合
设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...
- Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...
JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...
- aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...
- java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...
[Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...
- c++并发编程实战_Java 并发编程实战:JAVA中断线程几种基本方法
一个多线程Java程序,只有当其全部线程执行结束时(更具体地说,是所有非守护线程结束或者某个线程调用system.exit()方法的时候) ,才会结束运行.有时,为了终止程序或者取消一个线程对象所执行 ...
最新文章
- 反模式? 只有模式不彻底吧
- layui图片src 指定后没显示_2种方法用python调用cv2模块给图片打马赛克
- Android Bitmap开发之旅--基本操作
- 哈夫曼编码原理与Python实现代码(附手动推导过程原稿真迹)
- 极酷WIFI深度剖析免费WIFI
- 编译器错误不能找到元数据文件
- SVN 小乌龟(TortoiseSVN)本地文件更新报错Another process is blocking the working copy database 解决方法
- html ur是什么意思_url是什么意思?
- 好用的空气质量查询API
- java-喝饮料换空瓶问题
- 数据湖和数据仓库区别介绍
- thinkpad 重装--AHCI 导致系统蓝屏---迅盘
- 中国有句俗语叫“三天打鱼两天晒网”。某人从2010年1月1日起开始“三天打鱼两天晒网”, 问这个人在以后的某一天中是“打鱼”还是“晒网”。用C或C++语言/java/python实现程序解决问题
- matlab直流调速系统设计,直流调速系统的matlab设计与仿真系统设计
- python文件用pyinstaller库进行打包时,代码中用到的图片和我们自定义的python package包的处理办法
- 亚信科技Java后端实习
- matlab绘图(其他形式的二维曲线)
- H5 移动端 钉钉微应用 调用微信内置地图
- 【课程汇总】OpenHarmony全场景Demo数字管家系列课(附链接)
- windows常见问题汇集