- 可见性:一个线程对主内存的修改可以及时的被其他线程观察到。
- 有序性:一个线程观察其他线程中的指令执行顺序,由于指令 重排序的存在,该观察结果一般杂乱无序。
- 原子性:提供了互斥访问。
特性 | 操作 |
---|---|
可见性 | 可以由final(不会修改)、volatile(强制更新+读取主内存)以及synchronized(在unlock时会刷新所有已修改数据到主内存,lock时会从主内存重新加载数据)实现 |
有序性 | 可以由volatile(禁止指令重排序)/synchronized(一个变量最多只能有一个线程对其lock)实现 |
原子性 | 只有synchronized可以实现原子性,保证synchronized的代码块串行执行 |
synchronized在加锁时进行数据的重加载(主内存 -> 工作内存),在释放锁时将数据刷新到主内存。
冲突访问(Conflicting Accesses) 对同一个共享字段或数组元素存在两个访问(读或写),且至少有一个访问是写操作,就称作有冲突。当程序包含两个没有被 happens-before 关系排序的冲突访问时,就称存在数据争用。
动作A对于动作B是happen-before,即意味着动作A的修改(所有数据)对于动作B是可见的。
happens-before关系如下:
- 某个线程中的每个动作都 happens-before 该线程中该动作后面的动作(这里无论指令是否重排序都必须满足)。
- 某个管程 m 上的解锁动作 synchronizes-with 所有后续在 m 上的锁定动作(这里的后续是根据同步顺序定义的)。
- 对 volatile 变量 v 的写操作 synchronizes-with 所有后续任意线程对 v 的读操作(这里的后续是根据同步顺序定义的)。
- 用于启动一个线程的动作(start方法) synchronizes-with 该新启动线程中的第一个动作。
- 初始化动作对于其他线程的第一个调用是happen-before
- happen-before是闭包传递的。
数据争用的例子,左是正常的访问顺序,右是数据争用,由于存在错误的数据流,所以是一个错误的同步。