并发编程三特性-有序性性技术保障
3.1.有序性定义
有序性:即程序执行的顺序按照代码的先后顺序执行。
有前面的文章可知,JVM存在指令重排,所以存在有序性问题。
在Java中,由于happens-before原则,单线程内的代码是有序的,可以看做是串行(as-if-serial)执行的。但是在多线程环境下,多个线程的代码是交替的串行执行的,这就产生了有序性问题。
3.2.Java自带的有序性
在前面的文章可知,Java提供了happens-before原则保证程序基本的有序性,主要规则如下:
- 线程内部规则:在同一个线程内,前面操作的执行结果对后面的操作是可见的。
- 同步规则:如果一个操作x与另一个操作y在同步代码块/方法中,那么操作x的执行结果对操作y可见。
- 传递规则:如果操作x的执行结果对操作y可见,操作y的执行结果对操作z可见,则操作x的执行结果对操作z可见。
- 对象锁规则:如果线程1解锁了对象锁a,接着线程2锁定了a,那么,线程1解锁a之前的写操作的执行结果都对线程2可见。
- volatile变量规则:如果线程1写入了volatile变量v,接着线程2读取了v,那么,线程1写入v及之前的写操作的执行结果都对线程2可见。
- 线程start原则:如果线程t在start()之前进行了一系列操作,接着进行了start()操作,那么线程t在start()之前的所有操作的执行结果对start()之后的所有操作都是可见的。
- 线程join规则:线程t1写入的所有变量,在任意其它线程t2调用t1.join()成功返回后,都对t2可见。
而有序性问题,都是发生在happens-before原则之外的状况。
3.3.有序性问题示例
前置说明,其实网上有很多关于有序性的实例,类似如下:
通过运行结果发现,多线程环境中,代码是交替的串行执行的,这样会导致产生意料之外的结果。
3.4.有序性保障技术
在Java中提供了多种有序性保障措施,这里主要涉及两种:
- 通过synchronized关键字定义同步代码块或者同步方法保障可见性。
- 通过Lock接口保障可见性。