• Java并发_volatile实现可见性但不保证原子性


    读后感
    1. 介绍了volatile实现可见性的基本原理
    2. 介绍了volatile不能实现原子性的示例,volatile复合操作不能实现原子性,读取值后在自增前改值可能被其它线程读取并修改,自增后刷新值可能会覆盖其它线程修改后的值
    3. 介绍了实现原子性的三种方法及示例
      1. synchronized  修饰对象
      2. ReentrantLock 使用lock()、unlock()加锁解锁,比synchronized功能更多,JDK6后性能和synchronized差不多
      3. AtomicInteger  使用乐观锁


      volatile关键字:

    • 能够保证volatile变量的可见性
    • 不能保证volatile变量复合操作的原子性

      volatile如何实现内存可见性:

             深入来说:通过加入内存屏障和禁止重排序优化来实现的。

    • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令
    • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

             通俗地讲:volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,又会强迫线程将最新的值刷新到主内存。这样任何时刻,不同的线程总能看到该变量的最新值。

     

             线程写volatile变量的过程:

    • 改变线程工作内存中volatile变量副本的值
    • 将改变后的副本的值从工作内存刷新到主内存

             线程读volatile变量的过程:

    • 从主内存中读取volatile变量的最新值到线程的工作内存中
    • 从工作内存中读取volatile变量的副本

             volatile不能保证volatile变量复合操作的原子性:

    Java代码  收藏代码
    1. private int number = 0;  
    2. number++; //不是原子操作  

             它分为三步:
             读取number的值
             将number的值加1
             写入最新的number的值

     

              保证number自增操作的原子性:

    • 使用synchronized关键字
    • 使用ReentrantLock
    • 使用AtomicInteger

              使用synchronized关键字

    Java代码  收藏代码
    1. import java.util.concurrent.ExecutorService;  
    2. import java.util.concurrent.Executors;  
    3.   
    4. /** 
    5.  * @author InJavaWeTrust 
    6.  */  
    7. public class TestSyn implements Runnable {  
    8.   
    9.     private int number = 0;  
    10.   
    11.     public int getNumber() {  
    12.         return this.number;  
    13.     }  
    14.   
    15.     public void run() {  
    16.         increase();  
    17.     }  
    18.   
    19.     public void increase() {  
    20.         synchronized (this) {  
    21.             this.number++;  
    22.         }  
    23.     }  
    24.   
    25.     public static void main(String[] args) {  
    26.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
    27.         TestSyn syn = new TestSyn();  
    28.         for (int i = 0; i < 1000; i++) {  
    29.             exec.submit(syn);  
    30.         }  
    31.         System.out.println("number : " + syn.getNumber());  
    32.         exec.shutdown();  
    33.     }  
    34. }  

     

              使用ReentrantLock

    Java代码  收藏代码
    1. import java.util.concurrent.ExecutorService;  
    2. import java.util.concurrent.Executors;  
    3. import java.util.concurrent.locks.Lock;  
    4. import java.util.concurrent.locks.ReentrantLock;  
    5. /** 
    6.  * @author InJavaWeTrust 
    7.  */  
    8. public class TestRee implements Runnable {  
    9.   
    10.     private Lock lock = new ReentrantLock();  
    11.     private int number = 0;  
    12.   
    13.     public int getNumber() {  
    14.         return this.number;  
    15.     }  
    16.   
    17.     public void run() {  
    18.         increase();  
    19.     }  
    20.   
    21.     public void increase() {  
    22.         lock.lock();  
    23.         try {  
    24.             this.number++;  
    25.         } finally {  
    26.             lock.unlock();  
    27.         }  
    28.     }  
    29.   
    30.     public static void main(String[] args) {  
    31.         TestRee ree = new TestRee();  
    32.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
    33.         for (int i = 0; i < 1000; i++) {  
    34.             exec.submit(ree);  
    35.         }  
    36.         System.out.println("number : " + ree.getNumber());  
    37.         exec.shutdown();  
    38.     }  
    39. }  

     

              使用AtomicInteger

    Java代码  收藏代码
    1. import java.util.concurrent.ExecutorService;  
    2. import java.util.concurrent.Executors;  
    3. import java.util.concurrent.atomic.AtomicInteger;  
    4.   
    5. /** 
    6.  * @author InJavaWeTrust 
    7.  */  
    8. public class TestAtomic implements Runnable {  
    9.   
    10.     private static AtomicInteger number = new AtomicInteger(0);  
    11.   
    12.     public void run() {  
    13.         increase();  
    14.     }  
    15.   
    16.     public void increase() {  
    17.         number.getAndAdd(1);  
    18.     }  
    19.   
    20.     public static void main(String[] args) {  
    21.         TestAtomic ato = new TestAtomic();  
    22.         ExecutorService exec = Executors.newFixedThreadPool(1000);  
    23.         for (int i = 0; i < 1000; i++) {  
    24.             exec.submit(ato);  
    25.         }  
    26.         System.out.println("number : " + number.get());  
    27.         exec.shutdown();  
    28.     }  
    29. }  




  • 相关阅读:
    解决IE9下JQuery的ajax失效的问题
    npm更新到最新版本的方法
    animate.css配合wow.min.js实现各种页面滚动效果
    Bootstrap导航点击菜单跳转与点击缩放菜单折叠按钮缓冲效果插件jquery.singlePageNav.min.js
    对json对象进行截取并按照某关键字进行排序
    巧用 position:absolute
    EasyUI Datagrid 分页
    Cssreset
    杂记
    for循环遍历json(附习题及答案)
  • 原文地址:https://www.cnblogs.com/gossip/p/6182028.html
Copyright © 2020-2023  润新知