java多线程之volatile关键字
public class ThreadVolatile extends Thread {
public boolean flag=true;
@Override
public void run() {
System.out.println("子线程begin。。。。。。");
while(flag){}
System.out.println("子线程end。。。。。");
}
public void setFlag(boolean flag){
this.flag=flag;
}
public static void main(String[] args) throws InterruptedException {
ThreadVolatile threadVolatile=new ThreadVolatile();
threadVolatile.start();
Thread.sleep(3000);//作用是不立刻通知子线程、有延迟
threadVolatile.setFlag(false);
System.out.println("已经修改为false");//其实修改的是主内存里面的值,而threadVolatile中依然是副本也就是true
Thread.sleep(1000);
System.out.println(threadVolatile.flag);
}
}
运行上述代码输出如下:
子线程begin。。。。。。
已经修改为false
false
????发现并没有输出System.out.println("子线程end。。。。。");也就是说该线程并没有停止,程序一直running。
原因:线程之间是不可见的,读取的是副本,没有及时读取到主内存结果。主线程main修改了自己本地私有内存中flag的值为false并且刷新到主内存中,但是threadVolatile并没有及时从主内存中读取值而是读取本地私有内存,自然而然flag值为true,导致子线程threadVolatile一致无法停止
解决办法:使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值
将上述public boolean flag=true;修改为public volatile boolean flag=true;后即可得到如下输出结果:
子线程begin。。。。。。
已经修改为false
子线程end。。。。。
false
注意: Volatile非原子性
public class VolatileNoAtomic extends Thread {
//多个线程同时共享,static修饰关键字,存放在静态区,只会存放一次
private volatile static int count=0;
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
count++;
}
System.out.println(getName()+","+count);
}
public static void main(String[] args) {
VolatileNoAtomic[] volatileNoAtomics=new VolatileNoAtomic[10];
for (int i = 0; i < volatileNoAtomics.length; i++) {
volatileNoAtomics[i]=new VolatileNoAtomic();
}
for (int i = 0; i < volatileNoAtomics.length; i++) {
volatileNoAtomics[i].start();
}
}
}
程序输出如下结果:
Thread-1,1504
Thread-0,1504
Thread-2,2504
Thread-3,3504
Thread-4,4504
Thread-5,5504
Thread-6,6504
Thread-7,7504
Thread-8,8504
Thread-9,9504
平均运行10次左右会得到以上结果。数据不同步,这就说明了volatile不具备原子性。
public class VolatileNoAtomic extends Thread {
//多个线程同时共享,static修饰关键字,存放在静态区,只会存放一次
// private volatile static int count=0;
private static AtomicInteger count=new AtomicInteger(0);
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
// count++;
count.incrementAndGet();
}
System.out.println(getName()+","+count.get());
}
public static void main(String[] args) {
VolatileNoAtomic[] volatileNoAtomics=new VolatileNoAtomic[10];
for (int i = 0; i < volatileNoAtomics.length; i++) {
volatileNoAtomics[i]=new VolatileNoAtomic();
}
for (int i = 0; i < volatileNoAtomics.length; i++) {
volatileNoAtomics[i].start();
}
}
}
输出可能如下:线程间可见,有的还在++,有的直接System.out.println,但总会有10000
Thread-1,2000
Thread-0,2000
Thread-2,3000
Thread-3,4000
Thread-4,5000
Thread-5,6000
Thread-7,7000
Thread-8,8000
Thread-9,9000
Thread-6,10000
volatile与synchronized区别
仅靠volatile不能保证线程的安全性。(原子性)
①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。
线程安全性
线程安全性包括两个方面,①可见性。②原子性。
从上面自增的例子中可以看出:仅仅使用volatile并不能保证线程安全性。而synchronized则可实现线程的安全性。
java多线程之volatile关键字的更多相关文章
- Java多线程之volatile关键字《一》
关键字volatile的主要作用是使变量在多个线程间可见. 1.关键字volatile与死循环 如果不是在多继承的情况下,使用继承Thread类和实现Runnable接口在取得程序运行的结果上并没有什 ...
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- Java并发编程之volatile关键字解析
一内存模型的相关概念 二并发编程中的三个概念 三Java内存模型 四深入剖析volatile关键字 五使用volatile关键字的场景 volatile这个关键字可能很多朋友都听说过,或许也都用过.在 ...
- Java多线程之volatile详解
本文目录 从多线程交替打印A和B开始 Java 内存模型中的可见性.原子性和有序性 Volatile原理 volatile的特性 volatile happens-before规则 volatile ...
- Java 并发编程之volatile关键字解析
摘录 1. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执 ...
- Java并发编程之volatile关键字
大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...
- 多线程之volatile关键字(五)
开始全文之前,先铺垫一下jvm基础知识以及线程栈: JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolea ...
- JAVA多线程之Synchronized关键字--对象锁的特点
一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章 二,分析 s ...
- JAVA 多线程之volatile的介绍
volatile的介绍 volatile的主要作用是:提示编译器该对象的值有可能在编译器未监测的情况下被改变. volatile类似于大家所熟知的const也是一个类型修饰符.volatile是给编译 ...
随机推荐
- 文本情感分析(二):基于word2vec、glove和fasttext词向量的文本表示
上一篇博客用词袋模型,包括词频矩阵.Tf-Idf矩阵.LSA和n-gram构造文本特征,做了Kaggle上的电影评论情感分类题. 这篇博客还是关于文本特征工程的,用词嵌入的方法来构造文本特征,也就是用 ...
- H5易企秀
周末被领导叫回来加班,说要做一个易企秀一样的页面,然后就有这篇笔记 原计划用几百个计时器去执行,后面放弃了,太难改了,还是选择了animate.css插件,这是一个纯css的插件,只需要引入css就行 ...
- 《Netlogo多主体建模入门》笔记8
8 -GINI系数计算与 如何使用行为空间做实验 首先,我们加入保底机制. 对于每一个agent,都有一个随机的保底比例 s(每个agent的 s 不都一样,且s初始化之后不会改变) 进行交易 ...
- 洛谷 P2634 聪聪可可
题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...
- Day5 - F - 食物链 POJ - 1182
动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A.现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.有人用两种说法 ...
- SSM 整合配置以及一个简单登陆案例(个人记录)
SSM 文件以及大部分参考博客 https://blog.csdn.net/qq598535550/article/details/51703190 简答的登陆注册案例下载链接在末尾补贴图了 我建立的 ...
- 记录:JAVA抽象类、接口、多态
JAVA抽象类.接口.多态 1. 多态 定义 多态是同一个行为具有多个不同表现形式或形态的能力.(多态就是同一个接口,使用不同的实例而执行不同操作) 如何实现多态 继承和接口 父类和接口类型的变量赋值 ...
- webservice调试(XML参数)
<![CDATA[ <?xml version="1.0" encoding="UTF-8"?><MsgText> <use ...
- kNN.py源码及注释(python3.x)
import numpy as npimport operatorfrom os import listdirdef CerateDataSet(): group = np.array( ...
- JVM学习与问题总结——java内存区域与内存溢出异常
java虚拟机将内存分为哪些区域? 根据Java SE7版本的Java虚拟机规范,虚拟机管理的内存包括5个运行时数据区域: 程序计数器 虚拟机栈 本地方法栈 方法区 堆 运行时数据区各部分的作用? 程 ...