博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多线程 线程安全之volatile
阅读量:4961 次
发布时间:2019-06-12

本文共 1708 字,大约阅读时间需要 5 分钟。

 

Java线程安全主要是由两个特性来组成,1、原子性。2、可见性。

volatile关键字

原子性类似于数据库事务中的原子性,一个操作必须有始有终,不能中途被停止。

而可见性的意思:是多个线程之间访问共享变量时,A线程所修改的变量需要及时的被B线程或其他所有线程所读取到。

直接上代码,下面先看看当一个典型的多线程同步时的问题。

public class RunThread implements Runnable {    private boolean isRunning = true;    public boolean isRunning() {        return isRunning;    }    public void setRunning(boolean isRunning) {        this.isRunning = isRunning;    }    @Override    public void run() {        System.out.println("进入run了");        while (isRunning) {        }        System.out.println("线程被停止了!");    }    public static void main(String[] args) throws InterruptedException {        RunThread thread = new RunThread();        new Thread(thread).start();        Thread.sleep(100);        thread.setRunning(false);        System.out.println("已经赋值为false");    }}

输出结果:

 

根据代码,我们在main线程中已经设置isRunning为false,子线程thread应该跳出while的死循环,打印出“线程被停止了!”,而结果为什么没有呢?

这就引出了JMM 内存模型的主存和内存的关系问题,先看下JMM 内存模型的示意图。

 

可以看到,每个线程都拥有一个独立的本地内存(也可以叫工作内存),而下面大的主内存则是由所有线程所共享的,其实每次线程中所读取到的变量都是从主存中得来的,然后写入到自己的工作内存,然后进行操作。

基于这个模型,我们其实就可以回答上面的问题,在子线程中我们每次读取isRunning,都是从本地内存中,所有取得值一直是false,而在主线程中我们设置了isRunning为true是在主存中,子线程中没有及时的读取到主线程中改变的isRunning变量。这就造成了一个线程之间共享变量没有及时同步,也可以说是一个线程改变的值,没有及时被其他线程所看到。这里我们就引入了volatile关键字,只要被它修饰的变量在进行修改时,会向总线(BUS)发送消息,其他线程读取到该变量时,会得到最新的值。简单的来说,如果想要某个变量被所有线程读取到最新的值,就使用volatile关键字进行修饰。

所以在上面,我们仅仅需要在isRunning前面加上volatile关键字修饰,如下:

private volatile boolean isRunning = true;

 

 输出结果:

可以看到,程序已经如我们所预期的,达到线程安全的效果了。

volatile的局限性

其实volatile关键字解决的仅仅是线程之间可见性的问题,换句话说,它仅仅的解决的是线程之间数据能否被读取到,而没有解决多线程的原子性问题,即读到的数据是不是一个线程完整执行后的结果值。如果想保证多线程的原子性问题,可以参考java下的concurrent包下提供了一些原子类,如tomicInteger、AtomicLong、AtomicReference等,可以很好的解决变量数据的正确性问题。

 

转载于:https://www.cnblogs.com/qsymg/p/9837514.html

你可能感兴趣的文章
孤荷凌寒自学python第五十八天成功使用python来连接上远端MongoDb数据库
查看>>
求一个字符串中最长回文子串的长度(承接上一个题目)
查看>>
简单权限管理系统原理浅析
查看>>
springIOC第一个课堂案例的实现
查看>>
求输入成绩的平均分
查看>>
php PDO (转载)
查看>>
wordpress自动截取文章摘要代码
查看>>
[置顶] 一名优秀的程序设计师是如何管理知识的?
查看>>
scanf和gets
查看>>
highcharts 图表实例
查看>>
ubuntu下如何查看用户登录及系统授权相关信息
查看>>
秋季学期学习总结
查看>>
SpringBoot 优化内嵌的Tomcat
查看>>
【LaTeX】E喵的LaTeX新手入门教程(1)准备篇
查看>>
highcharts曲线图
查看>>
extjs动态改变样式
查看>>
PL/SQL Developer 查询的数据有乱码或者where 字段名=字段值 查不出来数据
查看>>
宏定义
查看>>
ubuntu12.04 串口登录系统配置
查看>>
poj3061
查看>>