ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java volatile关键字

2021-10-23 11:31:26  阅读:224  来源: 互联网

标签:lang Java public 关键字 race volatile java Method


volatile关键字的作用

  volatile关键字是Java虚拟机提供的最轻量级的同步机制,volatile具有可见性和有序性,但是,不具有原子性特性。

  Java中提供的操作运算符不具有原子性。

  看下面例子:

 

public class Main {

    public static volatile int race = 0;
    private static final int THREAD_COUNT = 10;

    public static void increase() {
        race++;
    }

    public static void main(String[] args) {
        final CountDownLatch downLatch = new CountDownLatch(THREAD_COUNT);

        Runnable runnable = () -> {
            for (int i = 0; i < 10000; i++) {
                increase();
            }

            downLatch.countDown();
        };

        Thread[] threads = new Thread[THREAD_COUNT];
        for (int i = 0; i < THREAD_COUNT; i++) {
            threads[i] = new Thread(runnable);
            threads[i].start();
        }

        try {
            downLatch.await();
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }

        System.out.println("end race = " + race);
    }

}

   结果:

    期望:100000

    输出:end race = 41573

  输出结果不到100000,不是期望值,通过javap反编译:

Compiled from "Main.java"
public class example.Main {
  public static volatile int race;

  public example.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void increase();
    Code:
       0: getstatic     #2                  // Field race:I
       3: iconst_1
       4: iadd
       5: putstatic     #2                  // Field race:I
       8: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #3                  // class java/util/concurrent/CountDownLatch
       3: dup
       4: bipush        10
       6: invokespecial #5                  // Method java/util/concurrent/CountDownLatch."<init>":(I)V
       9: astore_1
      10: aload_1
      11: invokedynamic #6,  0              // InvokeDynamic #0:run:(Ljava/util/concurrent/CountDownLatch;)Ljava/lang/Runnable;
      16: astore_2
      17: bipush        10
      19: anewarray     #7                  // class java/lang/Thread
      22: astore_3
      23: iconst_0
      24: istore        4
      26: iload         4
      28: bipush        10
      30: if_icmpge     58
      33: aload_3
      34: iload         4
      36: new           #7                  // class java/lang/Thread
      39: dup
      40: aload_2
      41: invokespecial #8                  // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
      44: aastore
      45: aload_3
      46: iload         4
      48: aaload
      49: invokevirtual #9                  // Method java/lang/Thread.start:()V
      52: iinc          4, 1
      55: goto          26
      58: aload_1
      59: invokevirtual #10                 // Method java/util/concurrent/CountDownLatch.await:()V
      62: goto          72
      65: astore        4
      67: aload         4
      69: invokevirtual #12                 // Method java/lang/InterruptedException.printStackTrace:()V
      72: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
      75: new           #14                 // class java/lang/StringBuilder
      78: dup
      79: invokespecial #15                 // Method java/lang/StringBuilder."<init>":()V
      82: ldc           #16                 // String end race =
      84: invokevirtual #17                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      87: getstatic     #2                  // Field race:I
      90: invokevirtual #18                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      93: invokevirtual #19                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      96: invokevirtual #20                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      99: return
    Exception table:
       from    to  target type
          58    62    65   Class java/lang/InterruptedException

  static {};
    Code:
       0: iconst_0
       1: putstatic     #2                  // Field race:I
       4: return
}

   着重看increase()方法:

public static void increase();
    Code:
       0: getstatic     #2                  // Field race:I
       3: iconst_1
       4: iadd
       5: putstatic     #2                  // Field race:I
       8: return

   在race变量读取和写入新值之间有“++”运算符操作,而Java运算符是不具有原子性的,导致race变量值出错。

  这不代表volatile的同步机制有错,只是因为volatile不具有原子性,volatile关键字修饰的变量只能保证可见性和有序性,在不能保证原子性操作的场景,依然需要使用synchronized、java.util.concurrent中的锁和原子类来保证原子性。

  volatile关键字在下面场景可以正常使用:

  • 运算结果不依赖当前值,或者保证只有一条线程修改变量值。
  • volatile修饰的变量不需要和其他状态变量参与不变约束。

 

标签:lang,Java,public,关键字,race,volatile,java,Method
来源: https://www.cnblogs.com/naray/p/15440130.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有