多线程读写共享变量时,synchronized与volatile的作用
在《effective java》中看的的知识点,在工作中确实遇到了~
keywordsynchronized能够保证在同一时刻,仅仅有一个线程能够运行某一个方法,或者某一个代码块。
同步并非单单指线程之间的相互排斥。
假设没有同步,一个线程的变化就不能被其它线程看到。
同步不仅能够阻止一个线程看到对象处于不一致的状态之中, 它还能够保证进入同步方法或者同步代码块的每一个线程,都看到由同一个锁保护的之前的全部改动效果。
思考以下这个程序的执行过程是什么样的。
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread =new Thread(new Runnable(){
public void run() {
int i=0;
while(!stopRequested){
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested=true;
}
}
你可能以为的这个程序大约执行一秒左右。之后主线程将stopRequested设置为true。从而导致后台线程终止。
可是结果不是这种。
问题在于,因为没有同步。就不能保证后台线程何时“看到”主线程对stopRequested的值所做的改变。Java语言规范保证读或写一个变量是原子的(atomic)long和double除外。可是它并不保证一个线程写入的值对于还有一个线程将是可见的。
以下看下解决方式
import java.util.concurrent.TimeUnit;
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop(){
stopRequested=true;
}
private static synchronized boolean stopRequested(){
return stopRequested;
}
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread =new Thread(new Runnable(){
public void run() {
int i=0;
while(!stopRequested()){
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
//stopRequested=true;
requestStop();
}
}
写入方法(requestStop())和读取(stopRequest())方法作 都被同步了 。仅仅同步写方法是不够的。实际上,假设读和写操作没有都被同步。同步就不会起作用。
StopThread中方法的同步是为了它的 通信效果 ,而不是为了相互排斥訪问。一种更加简洁,性能也可能更好的方法是将stopRequested声明为 volatile 。尽管volatile修饰符不运行相互排斥訪问,但 它能够保证不论什么一个线程在读取该field的时候都将看到近期刚刚被写入的值:
import java.util.concurrent.TimeUnit;
public class StopThread {
private static volatile boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread =new Thread(new Runnable(){
public void run() {
int i=0;
while(!stopRequested){
i++;
}
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested=true;
}
}
锁提供了两种主要特性:相互排斥(mutual exclusion) 和可见性(visibility)。
相互排斥即一次仅仅同意一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调訪问协议。这样,一次就仅仅有一个线程可以使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的还有一个线程是可见的 —— 假设没有同步机制提供的这样的可见性保证,线程看到的共享变量可能是改动前的值或不一致的值,这将引发很多严重问题。
Volatile 变量具有 synchronized 的可见性特性。这就是说线程可以自己主动发现 volatile 变量的最新值。
但要始终牢记使用 volatile 的限制
—— 仅仅有在状态真正独立于程序内其它内容时才干使用 volatile —— 这条规则可以避免将这些模式扩展到不安全的用例。
假设严格遵循
volatile 的使用条件 —— 即变量真正独立于其它变量和自己曾经的值 —— 在某些情况下能够使用 volatile 取代 synchronized 来简化代码
在多线程场景中。假设须要使用标记的时候。volatile往往能够大显身手~
多线程读写共享变量时,synchronized与volatile的作用的更多相关文章
- java多线程之内存可见性-synchronized、volatile
1.JMM:Java Memory Model(Java内存模型) 关于synchronized的两条规定: 1.线程解锁前,必须把共享变量的最新值刷新到主内存中 2.线程加锁时,将清空工作内存中共享 ...
- Java 多线程(二)synchronized和volatile
脏读: 脏读指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据.总的来说取到的数据是其实是被更改过的,但还没有保存到数 ...
- 多线程:Monitor、synchronized、volatile
Moniter的实现原理 再有人问你synchronized是什么,就把这篇文章发给他 深入理解Java中的volatile关键字 既生synchronized,何生volatile
- 【java多线程系列】java中的volatile的内存语义
在java的多线程编程中,synchronized和volatile都扮演着重要的 角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,可见性指的是当一 ...
- java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现
注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...
- synchronized 与 volatile 区别 还有 volatile 的含义
熟悉并发的同学一定知道在java中处理并发主要有两种方式: 1,synchronized关键字,这个大家应当都各种面试和笔试中经常遇到. 2,volatile修饰符的使用,相信这个修饰符大家平时在项目 ...
- Java多线程之内存可见性和原子性:Synchronized和Volatile的比较
Java多线程之内存可见性和原子性:Synchronized和Volatile的比较 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article ...
- java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析
java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...
- Java多线程同步方法Synchronized和volatile
11 同步方法 synchronized – 同时解决了有序性.可见性问题 volatile – 结果可见性问题 12 同步- synchronized synchronized可以在任意对象上加 ...
随机推荐
- [jobdu]丑数
由于思维的惯性,用了queue.后来发现一要注意要用集合判重,二是每次往queue里放的多,后来溢出了,要用long long.但这样要用数组,集合,队列,内存多.效率是O(n*logn)的. #in ...
- platform_driver与file_operations两种方法开发led驱动
下面是两个LED灯的驱动程序 一个用platform_driver 另一个用file_operations #include <linux/kernel.h> #include <l ...
- in on at 总结
in,on,at的时间用法和地点用法 一.in, on, at的时间用法 ①固定短语: in the morning/afternoon/evening在早晨/下午/傍晚, at noon/night ...
- IPv6 tutorial – Part 7: Zone ID and unique local IPv6 unicast addresses
The zone ID is used to distinguish ambiguous link-local and site-local addresses. Unique local IPv6 ...
- git checkout
git checkout <branch_name> <file> 检出具体分支上的 具体文件 git checkout --merge <branch_ ...
- 6个可以隐藏运行bat,浏览器等程序的方法
在电脑启动时或者设置时间时运行指定的程序很容易实现.但是有时候还需要运行时不显示主界面,隐藏到后台运行.比如:开机时一段Bat批处理执行删除默认共享; 开机自动运行浏览器隐藏到后代打开指定网页等,希望 ...
- -_-#【网站优化】AJAX
如何让搜索引擎抓取AJAX内容? Ajax 缓存: 两个重要的事实 使用 AJAX 事件触发 AJAX 请求.不要产生多次请求. 对 AJAX 请求使用 GET 方法 Use GET for AJAX ...
- apache开源项目--nutch
Nutch 是一个开源Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. Nutch的创始人是Doug Cutting,他同时也是Lucene.Hado ...
- Yet Another Scheme Introduction学习
Chapter 2 Function exact->inexact is to convert from fractional numbers to floating point numbers ...
- HDU 3416 Marriage Match IV dij+dinic
题意:给你n个点,m条边的图(有向图,记住一定是有向图),给定起点和终点,问你从起点到终点有几条不同的最短路 分析:不同的最短路,即一条边也不能相同,然后刚开始我的想法是找到一条删一条,然后光荣TLE ...