标签: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. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。