第一章 并发编程的挑战

0、挑战

并发编程的目的是让程序运行地更快,然而不是启动更多的线程就能让程序最大限度地并发执行。

为了达到目的,需要应对很多挑战:
1、上下文切换问题
2、死锁问题
3、硬件、软件的资源限制问题。

等等。

1、上下文切换

单核处理器在处理多线程代码时,CPU通过给每个线程分配CPU时间片来实现并发。CPU不停的切换线程执行,让程序员觉得多个线程在同时执行。每个时间片一般为几十毫秒。

CPU通过时间片分配算法来循环执行任务,当前任务执行完之后,会切换到下个任务。在切换状态前会保存上一个任务的状态,以保证下次切换到这个任务时,可以再加载该任务的状态。

任务的从保存到加载的过程就是一次上下文切换。

如何减少切换次数?

无锁并发编程:避免使用锁,比如将数据按id进行Hash后进行分段,不同的线程处理不同段的数据。 CAS算法:Atomic包使用的CAS算法来更新数据,需要加锁 控制线程数: 使用协程:在单线程里实现多任务的调度,维持多个任务间的切换。

2、资源限制问题

第二章 Java并发机制的底层实现原理

Java的并发机制依赖于JVM的实现和CPU的指令。

1、volatile应用

volatile 是轻量级的synchrionized,能够保证共享变量的“可见性”,比synchrionized的使用和执行成本更低,因此不会引起线程上下文的切换和调度。
可见性:当一个线程修改一个变量时,另外一个线程能读到这个修改的值。

volatile实现原理

相关的CPU术语:
image.png
原则:

1、将当前处理器缓存行的数据写回到系统内存 2、这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效

2、 synchronized

利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁:

1、普通同步方法,锁是当前实例对象 2、静态同步方法,锁是当前类的Class对象 3、同步方法快,锁是synchronized括号里配置的对象

当一个线程试图访问同步代码块时,必须得到锁,退出或抛出异常是必须释放锁