并发编程的优缺点
Posted pingping-joe
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程的优缺点相关的知识,希望对你有一定的参考价值。
1.并发编程的优点:
面对复杂业务模型,并行程序比串行程序更适应业务需求,而并发编程更吻合这种业务拆分,正是因为这些优点,使得多线程技术能够得到重视,也是一名CS学习者应该啊掌握的;
- 充分利用多喝CPU的计算能力
- 方便进行业务拆分,提升应用性能
2.并发编程的缺点:
多线程技术有这么多的好处,难道就没有一点缺点,就在任何场景下就一定适用么?很显然不是
2.1频繁的上下文切换
时间片是CPU分配给各个线程时间,因为时间非常短,所以CPU不断通过切换线程,让我们觉得多个线程是同时执行的,时间片一般是几十毫秒.而每次切换时,都要保存当前的状态,以便能够恢复先前状态,而这个切换是非常损耗性能的,过于频繁反而无法发挥多线程编程的优势.通常减少上下文切换可以采用无锁并发编程,CAS算法,使用最小的线程和使用协程.
- 无锁并发编程:可以参照concurrentHashMap锁分段的思想,不同的线程处理不同段的数据,这样在多线程竞争的条件下,可以减少上下文切换.
- CAS算法:利用Atomic下使用CAS算法来更新数据,使用了乐观锁,可以有效的减少一部分不必要的锁竞争带来的上下文切换.
- 使用最少线程:避免创建不需要的线程,比如任务很少,但是创建了很多的线程,这样会造成大量的线程都处于等待状态.
- 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换.
2.2线程安全
多线程编程中最难把握的就是临界区线程安全问题,稍微不注意就会出现死锁的情况出现,一旦产生死锁就会造成系统功能不可用.
public class DeadLockDemo { private static String resource_a = "A"; private static String resource_b = "B"; public static void main(String[] args) { deadLock(); } private static void deadLock() { Thread threadA = new Thread(new Runnable() { @Override public 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() { @Override public void run() { synchronized (resource_b) { System.out.println("get resource b"); synchronized (resource_a) { System.out.println("get resource a"); } } } }); threadA.start(); threadA.start(); } }
那么,通常可以用如下方式避免死锁的情况
- 避免一个线程同时获得多个锁.
- 避免一个线程在锁内部占有多个资源,尽量保证每个锁只占有一个资源.
- 尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时,当前线程不会阻塞.
- 对于数据锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况.
所以,如何正确的使用多线程编程技术有很大的学问,比如如何保证线程安全,如何正确理解由于JMM内存模型在原子性,有序性,可见性带来的问题,比如数据脏读,DCL等这些问题(在后续篇幅会讲述).在学习多线程编程技术的过程中会让你收获颇丰.所以要重视多线程编程.
以上是关于并发编程的优缺点的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段