Java并发编程的艺术:(1) 并发编程的挑战

并发编程的挑战

并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最大限度地并发执行。在进行并发任务让程序及执行更快的道路上会遭遇各种各样的挑战,那么我们该如何取舍并发呢?又该如何克服这些挑战呢?我们先从并发编程的应用场景说起。

并发编程的应用场景

提升性能

提升CPU的使用效率

一般来说一台主机上的会有多个CPU核心,我们可以创建多个线程,理论上讲操作系统可以将多个线程分配给不同的CPU去执行,每个CPU执行一个线程,这样就提高了CPU的使用效率,如果使用单线程就只能有一个CPU核心被使用。

即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以 CPU 通过不停地切换线程执行,让我们感觉多个线程是同时执行,时间片一般是几十毫秒。

降低系统的响应时间

同一个程序服务于多个用户,如果采用单线程,随着用户规模的扩大,访问时间靠后的用户需要等待的时间就会非常久。《软件测试技术大全》写到应用服务响应在 4s 以内用户是可以接受的,4 ~ 9 秒会流失 30% 的用户, 8 ~ 9 秒会流失 60% 的用户,10秒以上则会流失 90% 的用户。随着网络基础设施的完善和技术的发展,相信用户对等待时间这块要求会越来越高。

提升系统的容错能力

单线程有一个致命的问题,就是当进程崩溃后整个应用程序就会停止服务。而采用并发编程后,多线程各个线程在操作上是独立的,遭遇异常退出不会影响到其它线程。

并发编程带来的新挑战

上下文切换

CPU 通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加在这个任务的状态。所以任务从保存再加载的过程就是一次上下文切换。频繁的上下文切换也会影响系统系能,因此并发编程并不是线程数越多越好。在《并发编程的艺术》中作者对并发和串行做了一个循环累加测试,测试结果如下:

循环时间串行执行耗时 /ms并发执行耗时并发比串行快多少
1亿13077约 1 倍
1 千万189约 1 倍
1 百万55差不多
10万43差不多
1万01

从上表中可以发现,当并发执行累加操作不超过百万次时,速度会比串行执行累加操作要慢。慢是由多线程创建和上下文切换的开销造成的。

如何减少上下文切换

既然上下文切换会有一部分时间开销,那么如何减少这部分开销呢?作者给出了如下方法:

  • 无锁并发编程
  • CAS 算法
  • 使用最少线程
  • 协程

死锁

多线程涉及到资源共享的问题,对于读操作没有问题,但是读写操作就不行了。为了保证写的唯一性需要给资源加锁,多线程之间对于同一个锁之间是竞争关系。如果有多个这样的资源,那么锁的添加与释放会变的异常复杂,稍有不慎便会引起死锁造成系统功能不可用。

避免死锁的几个常见方法

多线程情况下避免死锁有如下常见方法:

  • 避免一个线程同时获取多个锁。
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
  • 尝试使用定时锁,使用lock.tryLock (timeout) 来替代使用内部锁机制。
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

资源限制的挑战

程序的执行速度受限于计算机硬件或软件资源,硬件资源包括:

  • CPU
  • 硬盘读写速率
  • 带宽

软件的资源限制包括:

  • 数据库的连接数
  • socket 连接数

硬件的限制可以通过改善硬件的方式解决,也可以通过调整架构的方式解决由集中式调整为分布式。
软件的限制,可以考虑资源的复用。比如使用数据库连接池和 Socket 连接复用。

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值