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. PYTHON 迭代器

    可以走直接作用于for循环的对象统称为可迭代对象使用:Iterable 使用isinstance()判断一个对象是否是Iterable对象: from collections import Itera ...

  2. [RouterOS] ROS对接碧海威或PA等流控实现完美流控详细教程(附脚本全免费)

    前言: 经常在群里看到不少朋友争论海蜘蛛 ROS 维盟 爱快 碧海威 流控大师 Woyos等等软路由,哪个好.实际上,网络产品是复杂的,现在的软路由功能上已经远远不是单独的路由了.每种产品都有他本身的 ...

  3. Codeforces Gym 101138 D. Strange Queries

    Description 给你一下长度为 \(n\) 的序列. \(a_i=a_j\) \(l_1 \leqslant i \leqslant r_1\) \(l_2 \leqslant i \leqs ...

  4. centos 随意截屏

    yum install kdegraphics 菜单路径: applications(应用程序)/Graphics(图形图像)/KSnapshot

  5. tornado 非阻塞方法

    http://sebastiandahlgren.se/2014/06/27/running-a-method-as-a-background-thread-in-python/

  6. wav转aac

    //调用neroAacEnc.exe STARTUPINFO si={}; PROCESS_INFORMATION pi={};//隐藏窗口 si.cb=sizeof(si); si.dwFlags= ...

  7. CentOS完美搭建Redis3.0集群并附测试

    线上的统一聊天和推送项目使用的是redis主从,redis版本2.8.6 redis主从和mysql主从目的差不多,但redis主从配置很简单,主要在从节点配置文件指定主节点ip和端口:slaveof ...

  8. Unity3d UGUI序列帧动画

    代码 using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine. ...

  9. 解读Unity中的CG编写Shader系列二

    转自 http://www.itnose.net/detail/6095974.html 上一篇文章的例子中我们可以看到顶点着色器的输出参数可以说是直接作为了片段着色器的形参传递过来,那么不由得一个问 ...

  10. 16. javacript高级程序设计-HTML5脚本编程

    1. HTML5脚本编程 l 跨文档消息传递API能够让我们在不降低同源策略安全性的前提下,在来至不同的域的文档间传递消息 l 原生拖放功能可以方便的指定某个元素是否可以拖动,并在放置时做出响应.还可 ...