Java 的另外一个经典书籍之一《Java 并发编程的艺术》大家肯定也是看过的,今天开始我按照我的理解通俗的讲解这本书。
首先并发编程的目的就是让程序跑的更快,但是并不是开启更多的线程就能让程序就能最大限度的并发执行,在实际的并发编程中,还会面临这很多的挑战,例如:上下文切换、死锁问题、硬件、软件的资源受限所带来的问题。
1、1 上下文切换
CPU通过给每个线程分配CPU时间片来执行多个线程,时间片一般非常的短,CPU通过不断的切换线程执行,所以让我们感觉多个线程是并发同时进行的,但是实际上并不是的。当前的任务执行了一个时间片后,保存当前的状态以便下一次再加载这个任务的状态,然后切换当下一个任务。所以任务从保存到再加载的过程就是一次上下文切换。然而上下文切换是需要时间的,会影响多线程的执行效率。
如何减少上下文切换
1、无锁并发编程。多线程竞争锁时,会引起上下文切换,没有竞争到锁的线程,一直处于等待状态,所以上下文切换的时间会比较长。所以可以使用一些方法避免使用锁。例如数据的ID利用Hash算法取模,不同的线程取不同的数据段。
2、CAS 算法。Java 的Atomic包就是使用的CAS算法更新数据,而不加锁。
3、使用最少线程。避免创建不必要的线程。
4、协程。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
1、2 死锁
在并发编程中很容易出现死锁,一旦出现死锁,系统功能就不能使用,书中介绍几种常见避免死锁的方式。
1、避免一个线程同时获得多个锁
2、保证一个锁只占用一个资源
3、尝试使用定时锁
4、数据裤锁,加锁和解锁i必须在同一个数据库连接中
1、3 资源限制的挑战
硬件资源的限制:可以用集群执行程序
软件资源的限制:使用连接池资源的复用
总结:
并发编程写的不严谨很容易出现问题、而且定位不太容易,所以书中建议多使用JDK并发包提供的并发容器和工具类来解决并发问题。