zoukankan      html  css  js  c++  java
  • java volatile进阶(一)

    本篇文章继续学习volatile。上篇文章简单的介绍了volatile和synchonized,这篇文章讲一下什么时候可以用volatile。

    先看一段代码。

    package com.chzhao.voltiletest;
    
    public class ChangeValue extends Thread {
    
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            GlobalValues.STATUS = "stop";
        }
    }
    package com.chzhao.voltiletest;
    
    public class VolatileDeep extends Thread {
    
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (GlobalValues.STATUS.equals("stop")) {
                    System.out.println(this.getName() + "stop");
                    GlobalValues.STATUS = "running";
                }
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new VolatileDeep();
            t1.setName("t1");
            t1.start();
    
            Thread t2 = new VolatileDeep();
            t2.setName("t2");
            t2.start();
    
            Thread t3 = new ChangeValue();
            t3.start();
        }
    }
    package com.chzhao.voltiletest;
    
    public class GlobalValues {
        public static String STATUS = "running";
    }

    这段代码很简单,输出的是什么呢?

    输出的是 t1stop?

    还是t2stop?

    还是

    t1stop
    t2stop

    ?

    真实的情况是以上三种都有可能。

    因为变量STATUS不是线程安全的,做为一个状态标识,在多线程的情况下状态是不可知的。

    但是,如果在变量前面加上volatile关键字。

    package com.chzhao.voltiletest;
    
    public class GlobalValues {
        public volatile static String STATUS = "running";
    }

    每次的都会输出

    t1stop
    t2stop

    当然,顺序不定。

    这说明,如果加了volatile关键字,作为标识状态是能够保证线程安全的。为什么呢?

    《Java 理论与实践: 正确使用 Volatile 变量》中介绍:

    Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。

    《深入理解Java虚拟机:JVM高级特性与最佳实践》中介绍:

    当一个变量定义为volatile之后,它将具备两种特性,第一是保证此变量对所有线程的可见性,这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量不能做到这一点,普通变量的值在线程间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成了之后再从主内存进行读取操作,新变量值才会对线程B可见。

    关于主内存,以后会有文章介绍。

    由上面两段文字可以知道,volatile有一个很好的特性-可见性,可以理解可见性是所有线程均可以立即得到变量的值。所以,在多线程情况下,用volatile修饰状态值是非常适合的。

    参考资料:

    《Java 理论与实践: 正确使用 Volatile 变量》

    《深入理解Java虚拟机:JVM高级特性与最佳实践》

  • 相关阅读:
    MySQL binlog 组提交与 XA(两阶段提交)
    mydumper 安装报错处理
    安装 gcc-c++ 时报错和原有 gcc 版本冲突
    mysql / mysqld_safe / mysqld 常见错误处理
    Linux 内核日志——dmesg
    Java中的Atomic包
    JAVA NIO中的Channels和Buffers
    字节流InputStream/OutputStream
    字符输出流Writer简要概括
    字符输入流Reader简要概括
  • 原文地址:https://www.cnblogs.com/wardensky/p/4154270.html
Copyright © 2011-2022 走看看