300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > java并发三大特性--有序性 可见性 原子性

java并发三大特性--有序性 可见性 原子性

时间:2020-12-05 05:57:32

相关推荐

java并发三大特性--有序性 可见性 原子性

在java并发编程中,我们一般会说需要满足以下三个基本条件才能构成java并发的基础,这三个特性分别是:有序性、可见性、原子性。那么这三个特性到底是一个怎么样的概念呢,下面我们将通过一些例子来详细说明一下这几个概念。

有序性:有序性是指在java并发中,如果执行编码的两条指令按照代码的先后顺序执行。设想一下,如果代码的执行顺序和我们看到的代码顺序不一样,那很可能会导致结果错乱。可为什么会导致代码执行和我们编写看到的不一样呢?这是因为编译器,处理器为了提升执行效率会对代码编译过后的执行指令进行重新排序(指令重排序)。在as-if-serial中规定了执行重排序一定要满足执行的结果不受指令排序的影响,编译器和处理器都会遵守这个规则,但是as-if-serial是针对单线程的,它只定义了单线程下指令重排序不能影响执行结果,对于多线程的情况下,有可能会导致执行结果不可预料。看下下面的demo,一个比较经典的双重检查单例:

publicclassSingleton{privatestaticSingletonsingleton;privateSingleton(){}publicstaticSingletonnewInstance(){if(singleton==null){synchronized(Singleton.class){if(singleton==null){singleton=newSingleton();}}}returnsingleton;}}

上面这个单例写法在极端情况下可能会导致问题,singleton不可用。原因在于:假设一个线程A执行第10行的时候,初始化一个singleton对象,如果了解java对象创建的同学应该知道,一个对象的创建有几个关键的步骤:1.申请内存空间,2.初始化对象3.将栈中singleton指向对象的地址;在这里编译器为了优化性能,可能会将2和3进行交换一下执行,这个在单线程的情况下不会有任何问题,但是在多线程的条件下,假设在线程A执行第三步的时候,线程B执行到第7行,发现这个对象不是null,就直接返回了,这个时候,该对象还没有初始化,那么久会导致线程B获取到的对象不可用。

上面是一个比较经典的指令重排序导致多线程问题,所以在多线程的情况下,有序的按照我们写的代码的执行是一个基本的前提条件。

可见性:在java语言中,每个线程都保留了一份用到的变量在本地缓存,而在主存中也有一份,其示意图如下:

如何保证线程A修改了变量值,线程B也能立马感应到,这就是可见性要描述的问题,在多线程的环境下,如果一个线程的本地副本值修改了,另一个线程能立马感知到这个变化,并且使用的是变化后的值,那么这样就构成了多线程的第二个基本概念:可见性。

原子性:第三个特性是指在执行一条指令的时候,对其他线程而言,要么执行成功,要么执行失败,没有中间状态,并且在执行的时候,其他线程是不能打断其执行的。这也有一个比较经典的例子:

inti=0;//只有这个是原子操作1)intb=i;// 2)i++;// 3)i=i+1;// 4)

上面有四行代码,只有第一行是原子性操作,在处理器中,它们能够保证从内存中读写单个字节是原子的,换句话说当一个核cpu在处理这块内存地址的时候,其他cpu是不能访问这个地址的,对于更复杂的操作,处理器能够提供总线锁定和缓存锁定来保证原子性,像第一行的代码,i =0;处理器提供一些相关的指令来保证原子性操作,XADD,BTS,CMPXCHG等,我们只需要调用这些指令就能保证这些操作一定是原子性操作,对于java程序员而言,我们需要了解的是CAS操作就是通过CMPXCHG指令实现原子性的。从这里可以看到,如果一个线程在执行的过程中,被另一个线程打断或者修改内存中的值,那就可能导致结果不正确。这就是构成java多线程并发的第三个基础:原子性。

当我们了解了java多线程是怎么一回事,了解了底层是怎么保证线程并发的可靠时,我们在看下这三个基本特性,就能明白理解这三个基本特性对理解java并发有多大的意义。

想要了解更多java内容(包含大厂面试题和题解)可以关注公众号,也可以在公众号留言,帮忙内推阿里、腾讯等互联网大厂哈。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。