加入收藏 | 设为首页 | 会员中心 | 我要投稿 吉安站长网 (https://www.0796zz.com.cn/)- 科技、图像处理、媒体智能、办公协同、操作系统!
当前位置: 首页 > 站长资讯 > 评论 > 正文

正在从全球数亿用户的500多个应用程序中窃取数据

发布时间:2021-02-17 11:33:07 所属栏目:评论 来源:互联网
导读:实际上,可以给flag加上volatile关键字,来保证有序性。当然,也可以通过synchronized和Lock来保证有序性。synchronized和Lock保证某一时刻是只有一个线程执行同步代码,相当于是让线程顺序执行程序代码了,自然就保证了有序性。 实际上Java内存模型的有序性

实际上,可以给flag加上volatile关键字,来保证有序性。当然,也可以通过synchronized和Lock来保证有序性。synchronized和Lock保证某一时刻是只有一个线程执行同步代码,相当于是让线程顺序执行程序代码了,自然就保证了有序性。

实际上Java内存模型的有序性并不是仅靠volatile、synchronized和Lock来保证有序性的。这是因为Java语言中,有一个先行发生原则(happens-before):

  • 「程序次序规则」:在一个线程内,按照控制流顺序,书写在前面的操作先行发生于书写在后面的操作。
  • 「管程锁定规则」:一个unLock操作先行发生于后面对同一个锁额lock操作
  • 「volatile变量规则」:对一个变量的写操作先行发生于后面对这个变量的读操作
  • 「线程启动规则」:Thread对象的start()方法先行发生于此线程的每个一个动作
  • 「线程终止规则」:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 「线程中断规则」:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 「对象终结规则」:一个对象的初始化完成先行发生于他的finalize()方法的开始
  • 「传递性」:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C

根据happens-before的八大规则,我们回到刚的例子,一起分析一下。给flag加上volatile关键字,look look它是如何保证有序性的,


 

  • 语句1操作显然是原子性的,将数值666赋值给i,即线程执行这个语句时,直接将数值666写入到工作内存中。
  • 语句2操作看起来也是原子性的,但是它实际上涉及两个操作,先去读j的值,再把j的值写入工作内存,两个操作分开都是原子操作,但是合起来就不满足原子性了。
  • 语句3读取i的值,加1,再写回主存,这个就不是原子性操作了。
  • 语句4 等同于语句3,也是非原子性操作。

可见性

  • 可见性就是指当一个线程修改了共享变量的值时,其他线程能够立即得知这个修改。
  • Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的,无论是普通变量还是volatile变量都是如此。
  • volatile变量,保证新值能立即同步回主内存,以及每次使用前立即从主内存刷新,所以我们说volatile保证了多线程操作变量的可见性。
  • synchronized和Lock也能够保证可见性,线程在释放锁之前,会把共享变量值都刷回主存。final也可以实现可见性。

有序性

Java虚拟机这样描述Java程序的有序性的:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中,观察另一个线程,所有的操作都是无序的。

后半句意思就是,在Java内存模型中,「允许编译器和处理器对指令进行重排序」,会影响到多线程并发执行的正确性;前半句意思就是「as-if-serial」的语义,即不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不会被改变。

比如以下程序代码:


 

(编辑:吉安站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读