JUC并发编程学习笔记 (8)

内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read和write操作在某些平台上允许例外)

lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态

unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用

load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

use (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令

assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用

write  (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

JMM对这八种指令的使用,制定了如下规则:

不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write

不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存

不允许一个线程将没有assign的数据从工作内存同步回主内存

一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作

一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁

如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值

如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量

对一个变量进行unlock操作之前,必须把此变量同步回主内存

java内存模型JMM理解整理

8中原子操作.png

volatile

volatile是Java关键字,是虚拟机提供的一种轻量级的同步机制。

保证可见性

不保证原子性

禁止指令重排

保证可见性

即只要我们的共享变量加上volatile关键字修饰,则可以保证该共享变量在各个工作内存中获取到的值时最新的值,通过CPU总线嗅探机制来实现。

不保证原子性

原子性指操作不可再分,不可分割。

即当线程在执行任务是不可被打扰,不可分割的,要么同时成功,要么同时失败。

代码示例 public class AtomicTest2 { //注意变量命令为int还是Integer在底层的汇编指令操作是不同的 private static volatile int num = 0; //原子类修饰 // private static volatile AtomicInteger num = new AtomicInteger(); public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(10); for (int i = 0; i < 10; i++) { new Thread(()->{ for (int j = 0; j < 1000; j++) { add(); } latch.countDown(); }).start(); } latch.await(); System.out.println(num); } public static void add(){ num++; } /* public static synchronized void add(){ num++; } public static void add(){ num.getAndIncrement(); }*/ /** * 只加volatile修饰 * 9600 * 加synchronized修饰 * 10000 * 更改为原子操作类计算 * 10000 */ } 反编译class文件查看底层原子操作

反编译命令如下:

D:\springboot-demo\target\classes\com\lai\springbootdemo\jmm>javap -c AtomicTest2.class

Compiled from "AtomicTest2.java" public class com.lai.springbootdemo.jmm.AtomicTest2 { public com.lai.springbootdemo.jmm.AtomicTest2(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]) throws java.lang.InterruptedException; Code: 0: new #2 // class java/util/concurrent/CountDownLatch 3: dup 4: bipush 10 6: invokespecial #3 // Method java/util/concurrent/CountDownLatch."<init>":(I)V 9: astore_1 10: iconst_0 11: istore_2 12: iload_2 13: bipush 10 15: if_icmpge 40 18: new #4 // class java/lang/Thread 21: dup 22: aload_1 23: invokedynamic #5, 0 // InvokeDynamic #0:run:(Ljava/util/concurrent/CountDownLatch;)Ljava/lang/Runnable; 28: invokespecial #6 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V 31: invokevirtual #7 // Method java/lang/Thread.start:()V 34: iinc 2, 1 37: goto 12 40: aload_1 41: invokevirtual #8 // Method java/util/concurrent/CountDownLatch.await:()V 44: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream; 47: getstatic #10 // Field num:I 50: invokevirtual #11 // Method java/io/PrintStream.println:(I)V 53: return public static void add(); Code: 0: getstatic #10 // Field num:I 3: iconst_1 4: iadd 5: putstatic #10 // Field num:I 8: return static {}; Code: 0: iconst_0 1: putstatic #10 // Field num:I 4: return

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxsxy.html