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关键字的更多相关文章

  1. Java多线程之volatile关键字《一》

    关键字volatile的主要作用是使变量在多个线程间可见. 1.关键字volatile与死循环 如果不是在多继承的情况下,使用继承Thread类和实现Runnable接口在取得程序运行的结果上并没有什 ...

  2. JAVA多线程之volatile 与 synchronized 的比较

    一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...

  3. Java并发编程之volatile关键字解析

    一内存模型的相关概念 二并发编程中的三个概念 三Java内存模型 四深入剖析volatile关键字 五使用volatile关键字的场景 volatile这个关键字可能很多朋友都听说过,或许也都用过.在 ...

  4. Java多线程之volatile详解

    本文目录 从多线程交替打印A和B开始 Java 内存模型中的可见性.原子性和有序性 Volatile原理 volatile的特性 volatile happens-before规则 volatile ...

  5. Java 并发编程之volatile关键字解析

    摘录 1. 计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执 ...

  6. Java并发编程之volatile关键字

    大概是因为项目.业务的原因,工作上几乎还没有使用过多线程相关的功能,相关知识差不多都忘了,所以最近补一下基础. volatile用来修饰共享变量,volatile变量具有 synchronized 的 ...

  7. 多线程之volatile关键字(五)

    开始全文之前,先铺垫一下jvm基础知识以及线程栈: JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolea ...

  8. JAVA多线程之Synchronized关键字--对象锁的特点

    一,介绍 本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点. 所谓对象锁,就是就是synchronized 给某个对象 加锁.关于 对象锁 可参考:这篇文章 二,分析 s ...

  9. JAVA 多线程之volatile的介绍

    volatile的介绍 volatile的主要作用是:提示编译器该对象的值有可能在编译器未监测的情况下被改变. volatile类似于大家所熟知的const也是一个类型修饰符.volatile是给编译 ...

随机推荐

  1. java中数组输出的方式

    方式1:遍历输出 public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 } ...

  2. Python调用Windows API函数编写录音机和音乐播放器

    功能描述: 1)使用tkinter设计程序界面: 2)调用Windows API函数实现录音机和音乐播放器. . 参考代码: ​ 运行界面: ​

  3. C语言中语句的跨行支持总结

    C语言中语句的跨行支持总结: 预处理一行写不下: 把一个预处理指示写成多行要用""续行,因为根据定义,一条预处理指示只能由一个逻辑代码行组成. 正常程序一行写不下: 把C代码写成多 ...

  4. Java 解决Emoji表情过滤问题

    Emoji表情从三方数据中获取没有过滤,导致存入DB的时候报错. 原因: UTF-8编码有可能是两个.三个.四个字节.Emoji表情是4个字节,而Mysql的utf8编码最多3个字节,所以数据插不进去 ...

  5. BAT 五路internet负载均衡

    一个网上下载的bat文件 也不记得从那里下载的了 记得似乎需要管理员权限运行 依稀记得测试有效 放在这里做个记录 @echo off echo. echo ╭─────────╮ echo ╭──── ...

  6. 应用于Oculus Quest的VR头显应用

    项目需要一个VR头显项目来展示算法成果,设备为Oculus Quest一体机,基于android平台(平台要切换为android),体验了下设备效果还行,但还是有点沙窗效应.记录一下开发流程. 先贴个 ...

  7. Linux系统sda变sdb的解决

    起因 我的电脑有一个128G的固态以及一个500G的机械,我将系统安装在128G固态中,于是将500G的机械(/dev/sdb)挂在在/home目录下,安装完系统后执行lsblk命令 NAME MAJ ...

  8. 小米手机收到升级鸿蒙OS提示?官方回应

    虽然尚未得到官方确认,但华为“鸿蒙”OS已经成为网络热门话题,在机圈引发热议. 本周,互联网上出现了显示为MIUI 10手机被锁定,屏幕上出现“小米将于2020年9月15日全面停止服务,届时您所有设备 ...

  9. Idea 打开多profile注意事项

    Maven项目经常会有多个profile,可以方便在编译时指定profile. 如果有多个profile,idea 在打开工程后默认配置可能会有些问题. 例如: 最近在编译一个项目:https://g ...

  10. ssh服务启动失败 /var/empty must be owned by root and not group or world-writable.

    输入 /etc/rc.d/init.d/sshd start 启动sshd服务,报如下错误: /var/empty must be owned by root and not group or wor ...