1.Java内存模型

现在计算机普遍使用多处理器进行运算,并且为了解决计算机存储设备和处理器的运算速度之间巨大的差距,引入了高速缓存作为缓冲,
缓存虽然能极大的提高性能,但是随之带来的缓存一致性的问题,
例如,当多个处理器同时操作同一个内存地址,可能会导致各自的缓存数据不一致,由此产生冲突问题,
内存模型就是定义一套充分必要的规范,这些规范使得其他处理器对内存的写操作对当前处理器可见,或者当前处理器的写操作对其他处理器可见。

类似物理上的计算机系统,Java虚拟机规范中也定义了一种Java内存模型,即Java Memory Model(JMM),来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。

现在最新的Java内存模型规范是JSR-133,即Java内存模型与线程规范

这套规范包含:
线程之间如何通过内存通信;
线程之间通过什么方式通信才合法,才能得到期望的结果。

2.线程间通信

线程间通信的方式有很多种,Windows下进程间通信及数据共享,这里只考察共享内存的方式。
对于Java的并发编程,线程间采用的是共享内存通信,
在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。

3.volatile关键字和内存结构

先看一下Java内存模型对应的内存结构:

线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本。

本地内存是一个抽象的概念,包括缓存、写缓冲区、寄存器等,

一个线程对 volatile 变量的写一定对之后对这个变量的读的线程可见,
即线程对 volatile 变量的读一定能看见在它之前最后一个线程对这个变量的写。

volatile包含以下语义:

(1)Java内存模型不会对valatile指令的操作进行重排序:这个保证对volatile变量的操作时按照指令的出现顺序执行的。
(2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方,每次总是从主存中读取volatile变量的结果。

为了实现这些语义,Java 规定,(1)当一个线程要使用共享内存中的 volatile 变量时,如图中的变量a,它会直接从主内存中读取,而不使用自己本地内存中的副本。(2)当一个线程对一个 volatile 变量进行写时,它会将这个共享变量的值刷新到共享内存中。

volatile 变量保证的是一个线程对它的写会立即刷新到主内存中,并置其它线程的副本为无效,它并不保证对 volatile 变量的操作都是具有原子性的

volatile 变量的写可以被之后其他线程的读看到,因此我们可以利用它进行线程间的通信。如

volatile int a;
public void set(int b) {
a = b;
}
public void get() {
int i = a;
}

线程A执行set()后,线程B执行get(),相当于线程A向线程B发送了消息。

volatile的语义,其实是告诉处理器,

不要将我放入工作内存,请直接在主存操作,多线程在访问该变量时,都将直接操作主存,这从本质上,做到了变量共享

4.synchronized关键字

synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A,没有的话,直接运行。
它包括两种用法:synchronized 方法和 synchronized 块。

5.final关键字

final关键字可以作用于变量、方法和类,我们这里只看final 变量。
final变量的特殊之处在于,final 变量一经初始化,就不能改变其值。
这里的值对于一个对象或者数组来说指的是这个对象或者数组的引用地址。因此,一个线程定义了一个final变量之后,其他任意线程都拿到这个变量。

但有一点需要注意的是,当这个final变量为对象或者数组时,
虽然我们不能讲这个变量赋值为其他对象或者数组,但是我们可以改变对象的域或者数组中的元素。
线程对这个对象变量的域或者数据的元素的改变不具有线程可见性。

Java内存模型对final有不用的重排序规则,final引用不能从构造函数内“逸出”。

参考

JAVA线程间通信简介

深入理解Java内存模型

volatile关键字与线程间通信的更多相关文章

  1. volatile关键字解决线程间内存共享变量同步的问题,让变量可以立即同步。

  2. 如何使用 volatile, synchronized, final 进行线程间通信

    原文地址:https://segmentfault.com/a/1190000004487149.感谢作者的无私分享. 你是否真正理解并会用volatile, synchronized, final进 ...

  3. Java多线程:线程间通信之volatile与sychronized

    由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信. Java为线程间通信提供了三个相关的关键字volatile, synchronized ...

  4. Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)

    一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...

  5. Java多线程:线程间通信之Lock

    Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...

  6. 关于java的volatile关键字与线程栈的内容以及单例的DCL

    用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值.volatile很容易被误用,用来进行原子性操作. package com.guangshan.test; pub ...

  7. VC 线程间通信的三种方式

    1.使用全局变量(窗体不适用)     实现线程间通信的方法有很多,常用的主要是通过全局变量.自定义消息和事件对象等来实现的.其中又以对全局变量的使用最为简洁.该方法将全局变量作为线程监视的对象,并通 ...

  8. 【转】VC 线程间通信的三种方式

    原文网址:http://my.oschina.net/laopiao/blog/94728 1.使用全局变量(窗体不适用)      实现线程间通信的方法有很多,常用的主要是通过全局变量.自定义消息和 ...

  9. Java多线程学习(五)线程间通信知识点补充

    系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...

随机推荐

  1. buildroot 添加ssh,以及使用stftp 服务

    上一篇水了一下关于buildroot的基本操作,这一章水一下开启SSH服务以及配置sftp服务,以及静态IP的设置. 配置: make menuconfig Target packages  ---& ...

  2. Kali Linux渗透基础知识整理(四):维持访问

    Kali Linux渗透基础知识整理系列文章回顾 维持访问 在获得了目标系统的访问权之后,攻击者需要进一步维持这一访问权限.使用木马程序.后门程序和rootkit来达到这一目的.维持访问是一种艺术形式 ...

  3. 项目: 推送水木文章到Kindle

    代码在github:https://github.com/Viyu/PushNewsmth2Mail 当年买Kindle的时候,想再Kindle上阅读水木的帖子,但Kindle的Web上网体验太差,想 ...

  4. 前端之css、JavaScript和DOM

    css position 一般组合 relative+absolute,以relative为父元素,absolute依照relative进行定位. opcity: 0.5 透明度 z-index: 层 ...

  5. 【GoLang】GoLang map 非线程安全 & 并发度写优化

    Catena (时序存储引擎)中有一个函数的实现备受争议,它从 map 中根据指定的 name 获取一个 metricSource.每一次插入操作都会至少调用一次这个函数,现实场景中该函数调用更是频繁 ...

  6. One Edit Distance

    Given two strings S and T, determine if they are both one edit distance apart. 分析:https://segmentfau ...

  7. js弹出提示信息,然后跳转到另一页面

    <script language="javascript">  alert("您的用户名与密码已成功修改!");  document.locatio ...

  8. 第十天 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)

    1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...

  9. Qt Connect 信号 槽

    信号和槽机制是 QT 的核心机制 .信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方.信号和槽是 QT 自行定义的一种通信机制,它独立于标准 ...

  10. How to call getClass() from a static method in Java?

    刚才在学习Java 使用properties类,遇到这样的错误: Cannot make a static reference to the non-static method getClass() ...