Synchronized之原子性、可见性、有序性

Synchronized与原子性

原子性是指一个操作是不可中断的,要全部执行完成,要不都不执行。

在Java中为了保证原子性,提供了两个高级的字节码指令moniterenter和moniterexit。这两个码指令,在Java对应的关键字是Synchronized。

线程1在执行moniterenter指令的时候,会对Monitor进行加锁,加锁后其它线程无法获得锁,除非线程1主动解锁。即使在执行过程中,由于某种原因,比如CPU时间片用完,线程1放弃了CPU,但是,他并没有进行解锁。而由于Synchronized的锁是可重入的,下一个时间片还是只能被他自己获取到,还是会继续执行代码,直到所有代码执行完,这就保证了原子性。

Synchronized与可见性

可见性是指多个线程访问同一个变量时,一个线程修改了这个变量的值,其它线程能够立即看到修改的值。

Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存保存了该线程需用变量主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间不能互相访问对方的工作内存中的变量,线程变量的传递均需要自己的工作内存和主内存之间进行数据同步。就有可能出线线程1改变了某个变量的值,但是线程2不可见的情况。

被Synchronized修饰的代码,在开始执行时人加锁,执行完成后会进行解锁。而为了保证可见性,有一条规则是这样的:对一个变量解锁之前,必须先把此变量同步回主存中。这样解锁后,线程就可以访问到被修改后的值。

所以Synchronized锁住的对象,其值具有可见性。

Synchronized与有序性

有序性即程序执行的顺序按照代码的先后顺序执行。

这里需要注意的是,synchronized是无法禁止指令重排和处理器优化的。也就是说,synchronized无法避免上述提到的问题。

那么,为什么还说synchronized也提供了有序性保证呢?

这就要再把有序性的概念扩展一下了。Java程序中天然的有序性可以总结为一句话:如果在本线程内观察,所有操作都是天然有序的。如果在一个线程中观察另一个线程,所有操作都是无序的。

以上这句话也是《深入理解Java虚拟机》中的原句,但是怎么理解呢?周志明并没有详细的解释。这里我简单扩展一下,这其实和as-if-serial语义有关。

as-if-serial语义的意思指:不管怎么重排序(编译器和处理器为了提高并行度),单线程程序的执行结果都不能被改变。编译器和处理器无论如何优化,都必须遵守as-if-serial语义。

这里不对as-if-serial语义详细展开了,简单说就是,as-if-serial语义保证了单线程中,指令重排是有一定的限制的,而只要编译器和处理器都遵守了这个语义,那么就可以认为单线程程序是按照顺序执行的。当然,实际上还是有重排的,只不过我们无须关心这种重排的干扰。

所以呢,由于synchronized修饰的代码,同一时间只能被同一线程访问。那么也就是单线程执行的。所以,可以保证其有序性。

你可能感兴趣的:(java,开发语言,后端)