《Java并发编程的艺术》读书笔记 第一章 并发编程的挑战
1。上下文切换
当我们使用多线程的方式执行代码的时候,CPU会给每个线程分配CPU时间片来实现。时间片就是CPU给每个线程分配的时间,时间片时间比较短,所以虽然CPU不停的来回切换线程,但我们依然感觉好像这些多线程是同时执行的。
当前任务执行一个时间片之后会切换到下一个任务,但是CPU分配的时间片能保证每个任务都在该时间内执行完吗?显然不一定,那就得记录一下切换前上一个任务的状态,以便下次切换回这个人物的时候,可以再加载这个任务的状态,所以任务从保存到再加载的过程就是一次上下文切换。
并发执行累计操作不超过百万次的时候,速度比串行执行累加操作要慢,因为线程有创建和上下文切换的开销。
如何减少上下文切换
减少的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。
无锁并发编程:如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
CAS算法:Java的Atomic包使用CAS算法来更新数据,而且不需要加锁。
使用最少线程:避免创建不需要的线程。
协程:在单线程里实现多任务的调度,并且在单线程里维持多个任务间的切换。
2。死锁
避免死锁的几个方法:
- 避免一个线程同时获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部所机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
3。资源限制的挑战
什么是资源挑战及引发的问题
在进行并发编程的时候,程序的执行速度受限于计算机硬件资源或者软件资源。如果将某段串行代码并发执行,受限于资源,仍然在串行运行,那么肯定比原来的串行执行慢,因为增加上下文切换和资源调度的时间。
如何解决
从两个方面考虑,一个是硬件方面,一个是软件方面。
对于硬件来说,考虑使用集群并行执行程序。对于软件来说,考虑使用资源池将资源复用,比如说连接池将数据库和Socket连接复用,或者在调用对方webservice接口获取数据的时候,只建立一个连接。