Java并发之三:并发概述

线程安全是一个比较复杂的概念。当多个线程访问某个类时,不受运行环境的调度方式和这些线程的交替执行顺序的影响,也不需要额外的同步,这个类都能表现出正确的行为,那么就认为它是线程安全的。常见的并发编程要么是用得太少未能发挥计算能力,要么就是使用不当,带来极大的风险。

线程安全的两个特性,原子性(atomicity)和 可见性(visibility)

原子性就是指对数据的操作是一个独立的、不可分割的整体。如果一次操作对应一条操作系统指令,这样肯定可以能保证原子性。但是很多操作不能通过一条指令就完成。int++ 就是一个典型的非原子操作 ,它对应的是三个动作:取值、在原值+1、写回。在并发环境下,往往在第二步就会遇到问题,原值已经被其他线程修改,当前线程仍旧将过时的“原值”+1后写回,导致得到一个无法预期的结果。非原子操作都存在线程安全问题。要保证组合操作的原子性,有三种方式: synchronized 、 Lock 、非阻塞算法(如CAS,比较并交换)。

要理解可见性,需要先对JVM的内存模型有一定的了解。简单来说,就是每个线程有私有的工作内存,变量会从共享内存拷贝过来,运算动作只能针对工作内存中的变量副本进行,完成后再将结果刷回共享内存。在并发环境下,如果多条线程同时操作一个共享变量的不同副本,某条线程对变量副本的修改结果,需要一个机制来确保其他线程能“看见”(并刷新自己的变量副本)修改后的最新值。

往下讨论之前,建议先了解以下两个主题:
1、Java并发之一:Java内存模型 
2、Java并发之二:JVM视角下的volatile

为了满足原子性、可见性,Java提供了四种不同的实现:volatile、原子类(Atomic)、同步(synchronized)、锁。

volatile是JVM提供的最轻量级的同步机制。volatile提供单个field的内存同步控制,synchronized则提供整个临界区(代码块/方法)的同步控制。volatile 确保了此变量对所有线程的实时可见性。普通变量做不到这一点,普通变量的值在线程间传递是异步的,需要通过主内存来完成。但 volatile 只提供了读写操作的原子性,没提供组合操作的原子性(如依赖原值的 int ++ )。正确地运用 volatile 必须考虑它的适用场景:运算结果并不依赖变量的当前值,或者能够确保只有单一线程修改变量的值。

原子变量类可以认为是 volatile 变量的泛化,它主要通过volatile和硬件支持的CAS算法来支持原子条件的比较并设置更新。原子变量类的另一个更重要的用途是构建高效的非阻塞算法。非阻塞算法用底层的原子机器指令代替锁来确保数据在并发访问中的一致性。与基于锁的方案相比,非阻塞算法在设计和实现上要复杂得多,但它的可伸缩性和活跃性上拥有较大优势。

同步(synchronized),每个对象或类有一个隐式锁,每次进入synchronized临界区时获取或阻塞等待该锁,退出时释放锁。隐式锁是互斥锁,每次只能有一个线程获取,未释放之前其他线程要么阻塞等待直到对方释放,要么放弃。早期的 synchronized 实现很重,性能不佳。Java 5/6引入锁升级的机制进行了优化。此外,synchronized 也有不少功能性的限制 —— 它无法中断一个正在等候获得锁的线程,也无法通过轮询得到锁。对此,Java在JUC包中引入了Lock 框架。

Lock 框架 是同步的兼容替代品,提供了与synchronized关键字类似的同步功能。Lock在使用时需要显式地获取和释放锁。虽然缺少了隐式锁的便捷性, 但是却拥有了锁获取与释放的可操作性、 可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性,允许编程人员对锁管理进行更细致的控制。Lock接口的实现基本都是通过聚合了一个同步器的子类来完成线程访问控制的。说到同步器,就要去了解AQS(AbstractQueuedSychronizer),AQS与CAS构成了JUC包的核心。仔细分析JUC包的源代码实现,会发现一个通用的实现模式:

首先,声明共享变量为volatile;
然后,使用CAS的原子条件更新来实现线程之间的同步;
同时,利用volatile的读/写和CAS配合实现线程之间的通信。

AQS、非阻塞数据结构和原子变量类,这些基础类都是使用这种模式来实现的,而高层类又是依赖于这些基础类来实现的。

java.util.concurrent 包实现示意图

以上这些内容,再加上线程创建(Thread/Runnable/Callable)、运行管理(Executor框架)、容器(阻塞队列、线程安全集合)等,这就是Java并发机制的索骥图了。


参考:
1、《Java并发编程实战》Brian Goetz等人
2、《Java思想与实践》Brian Goetz 
3、JAVA CAS原理深度分析

你可能感兴趣的:(Java并发之三:并发概述)