volatile关键字解析(二)
volatile详解
接下来,我们详细讲述一下volatile关键字
volatile关键字具有两重语义
- 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其他线程来说是立即可见的。
- 禁止指令重排序
依然使用上文RunThread案例说明,上文中已经提到了,由于主线程修改了isRunning的值后,RunThread线程并没有看到其值的变化,因此,进入了死循环,但是当isRunning加上volatile关键字后,效果就不一样了。
- 使用volatile关键字会强制将修改的值立即写入主存;
- 使用volatile关键字的话,当主线程修改时,会导致RunThread的工作内存中isRunning变量的缓存值变得无效。
- 由于RunThread的工作内存中缓存变量isRunning缓存无效,所以会再次从主存中读取isRunning变量值。
这样就保证了RunThread可以顺利结束。
关于原子性,我们先看个例子:
public class TestCount
{
private volatile int n; public void increase()
{
n ++;
} public static void main(String[] args)
{
TestCount count = new TestCount();
for(int i=0; i<10; i++)
{
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
count.increase();
};
}.start();
} if(Thread.activeCount() > 1)
{
Thread.yield();
}
System.out.println(count.n);
}
}
关于这个结果,应该很多人会认为是10000吧。但是实际上,运行结果小于10000,这是由于n++操作并非原子性操作,其涉及三个操作
- 读出n的旧知
- 对n+1
- 写入新值
虽然volatile可以保证每个线程读取到的是最新的内存值,但是,如果10个线程第一步都是正确的,第二步和第三步单线程看的话也都是没有问题的,但是如果并发的话,就会导致同一个值被多次写入了内存。
可见volatile并不能保证原子性操作。
对于这一类问题,我们可以通过synchronized、lock或者原子操作类经行操作。
synchronized版本:
public class TestCount
{
public int inc = 0; public synchronized void increase() {
inc++;
} public static void main(String[] args) {
final TestCount test = new TestCount();
for(int i=0;i<10;i++){
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
test.increase();
};
}.start();
} while(Thread.activeCount()>1) //保证前面的线程都执行完
Thread.yield();
System.out.println(test.inc);
}
}
lock版本:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class TestCount
{
public int inc = 0;
Lock lock = new ReentrantLock(); public void increase() {
lock.lock();
try {
inc++;
} finally{
lock.unlock();
}
} public static void main(String[] args) {
final TestCount test = new TestCount();
for(int i=0;i<10;i++){
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
test.increase();
};
}.start();
} while(Thread.activeCount()>1) //保证前面的线程都执行完
Thread.yield();
System.out.println(test.inc);
}
}
原子操作类版本:
import java.util.concurrent.atomic.AtomicInteger; public class TestCount
{
public AtomicInteger inc = new AtomicInteger(); public void increase() {
inc.getAndIncrement();
} public static void main(String[] args) {
final TestCount test = new TestCount();
for(int i=0;i<10;i++){
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
test.increase();
};
}.start();
} while(Thread.activeCount()>1) //保证前面的线程都执行完
Thread.yield();
System.out.println(test.inc);
}
}
对于有序性,我们可以看下下面的这个例子:
//线程1:
context = loadContext(); //语句1
inited = true; //语句2 //线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
如果没有对inited加volatile关键字,则可能会对语句1和语句2进行调整,因此两者并无依赖关系,并且单线程下,也并不会影响结果。但是两个线程下,可能由于context并没有初始化完成,导致意想不到的结果。
如果对inited加上volatile,这个问题就不会发生了。语句1和语句2的执行顺序则不会被调整。
volatile关键字解析(二)的更多相关文章
- Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- (转)Java并发编程:volatile关键字解析
转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...
- volatile关键字解析(转)
volatile关键字解析 转载:http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在J ...
- Java并发编程:volatile关键字解析(转载)
转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 ...
- Java并发编程学习:volatile关键字解析
转载:https://www.cnblogs.com/dolphin0520/p/3920373.html 写的非常棒,好东西要分享一下 Java并发编程:volatile关键字解析 volatile ...
- Java并发编程:volatile关键字解析-转
Java并发编程:volatile关键字解析 转自海子:https://www.cnblogs.com/dayanjing/p/9954562.html volatile这个关键字可能很多朋友都听说过 ...
- Java并发编程之三:volatile关键字解析 转载
目录: <Java并发编程之三:volatile关键字解析 转载> <Synchronized之一:基本使用> volatile这个关键字可能很多朋友都听说过,或许也都用过 ...
- Java 并发:volatile 关键字解析
摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...
- 6、Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- 转:Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字, ...
随机推荐
- HBuilder android 打包指南(V客学院技术分享)
前提:确保配置文件(manifest.json)已配置完,没有异常. 打包选项如下: Android 包名 :在Android系统中是判断一个App的唯一标识,不同的App可以有同样的名字,但是它的包 ...
- PHP递归算法
/** * 获取菜单 * @param number $id * @return multitype: */ public function menu($id = 0) { $menu = M ( ' ...
- windows忘记密码
方法一 在开机时,按下F8进入”带命令提示符的安全”模式 输入”NET USER+用户名+123456/ADD”可把某用户的密码强行设置为”123456″ 方法二 如用户忘记登入密码可按下列方法解决 ...
- 在VMware中使用Nat方式设置静态IP
为了在公司和家中不改变ip,所以采用vm的NAT模式来设置静态ip 1.vm采用NAT模式联网 2.编辑vm虚拟机设置 3.查看该网段的网关 可以看出网关为192.168.44.2,然后开始设置静态i ...
- IT最新最火的网络词汇*2*(文章来源电商)
P2P.P2C .O2O .B2C.B2B.C2C等等最新最火的网络用词直接将我们都弄晕了,特此今天将这些划时代意义的词汇总结起来,若有什么不足之处,希望各位评论指正. 大致意思为: 1. ...
- swift设计模式学习 - 装饰模式
移动端访问不佳,请访问我的个人博客 设计模式学习的demo地址,欢迎大家学习交流 装饰模式 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真 ...
- Ice Cream Tower
2017-08-18 21:53:38 writer:pprp 题意如下: Problem D. Ice Cream Tower Input file: Standard Input Output f ...
- SpringBoot创建定时任务
之前总结过spring+quartz实现定时任务的整合http://www.cnblogs.com/gdpuzxs/p/6663725.html,而springboot创建定时任务则是相当简单. (1 ...
- location的部分属性
http://www.w3school.com.cn/jsref/dom_obj_location.asp location.host 可以设置或返回主机名和当前url的端口 www.w3sch ...
- ThinkPHP开发笔记-用户登录注册
1.修改模块配置,Application/当前模块名/Conf/config.php <?php return array( //数据库配置信息 'DB_TYPE' => 'mysql', ...