volatile关键字与线程间通信

Java内存模型

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

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

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

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

线程间通信

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

volatile关键字和内存结构

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

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

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

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

volatile包含以下语义:

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

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

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

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


1

2

3

4

5

6

7

volatile int a;

public void set(int b) {

a = b;

}

public void get() {

int i = a;

}

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

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

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

>>synchronized关键字

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

final关键字

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

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

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

 

时间: 2024-10-24 05:18:11

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

深入解析Java的线程同步以及线程间通信_java

Java线程同步 当两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被一个线程占用.达到此目的的过程叫做同步(synchronization).像你所看到的,Java为此提供了独特的,语言水平上的支持. 同步的关键是管程(也叫信号量semaphore)的概念.管程是一个互斥独占锁定的对象,或称互斥体(mutex).在给定的时间,仅有一个线程可以获得管程.当一个线程需要锁定,它必须进入管程.所有其他的试图进入已经锁定的管程的线程必须挂起直到第一个线程退出管程.这些其他的线程被

C++多线程编程(三)线程间通信

多线程编程之三--线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707   七.线程间通讯 一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信.这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明. 使用全局变量进行通信 由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间

什么是.Net的异步机制(线程间通信)

前几篇文章我已经对异步的操作进行的详细的解释.异步操作也是线程的一种,当我们开始一个异步操作(新线程),完成调用后需要和其他线程通信(可能需要告知状态信息),这时候我们就需要线程间的通信编程. 线程间通信 我们看下面的图 图1 我们来看线程间通信的原理:线程(Thread B)和线程(Thread A)通信, 首先线程A 必须实现同步上下文对象(Synchronization Context), 线程B通过调用线程A的同步上下文对象来访问线程A,所有实现都是在同步上下文中完成的.线程B有两种方式

java线程间通信[实现不同线程之间的消息传递(通信),生产者和消费者模型]

线程通信,线程之间的消息传递: 多个线程在操作同一个资源,但对共享资源的操作动作不同:它们共享同一个资源,互为条件,相互依赖,相互通信让任务向前推进. 线程的同步,可以解决并发更新同一个资源,实现线程同步;但不能用来实现线程间的消息传递. 线程通信生产者和消费者和仓库是个典型模型: 生产者:没有生产之前通知消费者等待,生产产品结束之后,马上通知消费者消费 消费者:没有消费之前通知生产者等待,消费产品结束之后,通知生产者继续生产产品以供消费 线程通信:使用java中Object中提供的: publ

Android线程间通信之handler

本文讲的是Android线程间通信之handler,相信写过android的童鞋,一定对handler很熟悉.因为使用频率实在太高了.尤其是在非ui线程,想要刷新ui控件的时候.因为ui控件的刷新只能在主线程做,但是我们可能有在非ui线程却需要更新ui的需求,比如在一个后台线程下载了图片需要更新到ui上,这时候就需要主线程handler来发送更新的message. handler的使用如此频繁,我们有必要知道其内部是如何工作的. 一句话概括 handler thread handler 发送什么

代码-Qt中使用WinThread通常如何实现线程间通信如传递QByteArray

问题描述 Qt中使用WinThread通常如何实现线程间通信如传递QByteArray 因为多线程要写在一个类里,并且考虑效率.需要使用WinThread.初学Qt,恳请各位前辈赐教.最好有代码,万分感谢! 解决方案 PostThreadMessage在线程之间发送数据

深入Android Handler与线程间通信ITC的详解_Android

在<Android Handler之消息循环的深入解析>中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间通信ITC,这种方式更加安全和高效,可以大大减少同步的烦恼,甚至都可以不用syncrhonized.线程间通讯ITC正常情况下函数调用栈都会生存在同一个线程内,想要把执行逻辑交换到其他线程可以新建一个Thread,然后start().另外一种方法就是用ITC,也即用消息队列来实现,线程需要把执行逻辑交到其他线程时就向另外的线程的消息队列发送一个消息,发送消

java线程间通信

线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 例如,线程B可以等待线程A的一个信号,这个信号会通知线程B数据已经准备好了.本文将讲解以下几个JAVA线程间通信的主题: 1.通过共享对象通信 2.忙等待 3.wait(),notify()和notifyAll() 4.丢失的信号 5.假唤醒 6.多线程等待相同信号 7.不要对常量字符串或全局对象调用wait() 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值.线程A在一

Python多线程编程(八):使用Event实现线程间通信_python

使用threading.Event可以实现线程间相互通信,之前的Python:使用threading模块实现多线程编程七[使用Condition实现复杂同步]我们已经初步实现了线程间通信的基本功能,但是更为通用的一种做法是使用threading.Event对象.使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False.一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set