• 144990

    文章

  • 856

    评论

  • 13

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

Java多线程 线程安全之volatile


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

 

1.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;

输出结果:

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

2.volatile的局限性

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


695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤 主体内容背景
打开支付宝扫码付款购买视频教程
遇到问题联系客服QQ:419400980
注册梁钟霖个人博客