19Java多线程之并发编程三大特性
原子性
原子是世界上的最小单位,具有不可分割性。
比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。
非原子操作都会存在线程安全问题,需要我们使用同步技术(synchronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。
如果把一个事务看作是一个程序,要么全部执行,要么全不执行。这种特性就叫原子性。
在 Java 中 synchronized 和在 lock、unlock 中的操作保证了原子性。
concurrent 包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
扩展链接:
[Redis的单个操作是原子性的,多个操作支持事务](https://www.runoob.com/redis/redis-intro.html#:~:text=原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。)
可见性
可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程修改共享变量后,还没有来的及将缓存中的变量刷新到主存,另外一个线程就对共享变量进行修改,那么这个线程拿到的值是主存中未被修改的值,这就是可见性的问题。
可见性,指线程间内存的可见性,一个线程的修改,对另一个线程立马可见。
在 Java 中 volatile、synchronized 实现可见性。
可见性问题示例:
1 | public class Test { |
有序性
Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性。
volatile 是因为其本身包含 禁止指令重排序
的语义。
synchronized 是由 一个变量在同一个时刻只允许一条线程对其进行 lock 操作
这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。