• jvm-synchronized和volatile


    synchronized

    进入、退出同步块时会刷新所有工作内存,使得其他线程对刚退出同步块的线程对共享变量所作的更新可见。通过锁机制,synchronized实现了原子性和有序性,即同一时刻只能有一个线程进入临界区,且保证了下一个线程进入临界区之前上一个线程已经退出临界区。

    volatile

    同样通过刷新工作内存,实现了可见性,通过禁止指令重排序实现了有序性(个人理解:首先禁止编译器对jvm指令编译成机器指令时的重排序,其次禁止cpu执行机器指令时的指令重排序)。

      1 public class TestSynchronizedAndVolatile {
      2     private boolean b = false;
      3     private volatile Object lock = new Object();
      4 
      5     /**
      6      * 普通变量的写操作,不但会写入缓存,还会写回主内存
      7      */
      8     @Test
      9     public void test1() throws InterruptedException {
     10         new Thread(new Runnable() {
     11             @Override
     12             public void run() {
     13                 try {
     14                     /**
     15                      * 为了判断主线程中b=true是写入了主内存,还是仅写入工作内存。
     16                      * 之后的循环会跳出,说明了主线程中b=true回写到了主内存中。
     17                      */
     18                     Thread.sleep(100);
     19                 } catch (InterruptedException e) {
     20                 }
     21                 while (true) {
     22                     if (b) {
     23                         break;
     24                     }
     25                     b = false;
     26                 }
     27                 System.out.println("end");
     28             }
     29         }).start();
     30         b = true;
     31         Thread.sleep(1000);
     32     }
     33     /**
     34      * 线程中第一次读取到共享变量后,该变量会缓存在工作内存中,
     35      * 再次访问时直接从工作内存中读取,而不会重新从主内存中读取。
     36      * 这就造成了多线程访问共享变量时,访问到的是旧值。
     37      */
     38     @Test
     39     public void test2() throws InterruptedException {
     40         new Thread(new Runnable() {
     41             @Override
     42             public void run() {
     43                 while (true) {
     44                     /**
     45                      * 主线程中b=true后于子线程执行,虽然b=true已经作用于主内存,
     46                      * 但此前子线程已经将b读入工作内存(缓存),子线程没有动机再次从主线程同步b,
     47                      * 故这里会无限循环
     48                      */
     49                     if (b) {
     50                         break;
     51                     }
     52                 }
     53                 System.out.println("end");
     54             }
     55         }).start();
     56         Thread.sleep(100);
     57         b = true;
     58         Thread.sleep(100);
     59     }
     60 
     61     /**
     62      * synchronized会刷新缓存
     63      */
     64     @Test
     65     public void test3() throws InterruptedException {
     66         new Thread(new Runnable() {
     67             @Override
     68             public void run() {
     69                 Object lock = new Object();
     70                 while (true) {
     71                     /**
     72                      * 加入synchronized同步后情况发生了改变,当b=true同步回主内存后,
     73                      * 子线程中的b与主内存的值相同,循环跳出。
     74                      * 可见进入synchronized时会刷新工作内存(所有线程的工作内存),从而使得读取b时必须从主内存读取。
     75                      */
     76                     synchronized (lock) {
     77                         if (b) {
     78                             break;
     79                         }
     80                     }
     81                 }
     82                 System.out.println("end");
     83             }
     84         }).start();
     85         Thread.sleep(100);
     86         b = true;
     87         Thread.sleep(100);
     88     }
     89 
     90     /**
     91      * volatile会刷新缓存
     92      * @throws InterruptedException
     93      */
     94     @Test
     95     public void test4() throws InterruptedException {
     96         new Thread(new Runnable() {
     97             @Override
     98             public void run() {
     99                 Object obj = null;
    100                 while (true) {
    101                     /**
    102                      * 加入synchronized同步后情况发生了改变,当b=true同步回主内存后,
    103                      * 子线程中的b与主内存的值相同,循环跳出。
    104                      * 可见进入synchronized时会刷新工作内存(所有线程的工作内存),从而使得读取b时必须从主内存读取。
    105                      */
    106                     if (b) {
    107                         break;
    108                     }
    109                     System.out.println(b);
    110                     /**
    111                      * 由于lock是一个volatile,为了读到最新的lock值,这里就会刷新工作内存,
    112                      * 这样的话,当再次进入循环时,b就需要从主内存读取,所以可以跳出循环。
    113                      * (这里只体现了volatile可见性的语义,并没有体现禁止指令重排序的语义,
    114                      * 个人对指令重排序的理解分为两层,一层是编译器将jvm指令转换为机器指令时的重排序,
    115                      * 另一层是多核cpu并行执行指令造成的指令执行顺序的乱序。
    116                      * 而可见性则可以通过刷新所有线程的工作内存实现。)
    117                      */
    118                     obj = lock;
    119                     System.out.println("lock");
    120                 }
    121                 System.out.println("end");
    122             }
    123         }).start();
    124         Thread.sleep(10);
    125         b = true;
    126         Thread.sleep(100);
    127     }
    128 }
  • 相关阅读:
    指针问题,p+i什么意思i代表什么
    怎么用C语言写一个飞机程序
    switch()语句中()中必须是常量吗
    一元二次方程运行结果中输入上系数后总显示输入不合法无论系数可以得出实根
    我想学号图论求大神请教
    c-freelib库
    十进制转十六进制问题(有代码)
    关于逐个读取同一目录下txt文本的问题
    JAVA-JDK1.7-ConCurrentHashMap-测试和验证
    JAVA-JDK1.7-ConCurrentHashMap-源码并且debug说明
  • 原文地址:https://www.cnblogs.com/holoyong/p/7485546.html
Copyright © 2020-2023  润新知