中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Java中無鎖技術

發布時間:2021-11-01 14:44:32 來源:億速云 閱讀:100 作者:iii 欄目:編程語言

本篇內容介紹了“如何使用Java中無鎖技術”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、原子工具類

JDK 1.8 中,java.util.concurrent.atomic 包下類都是原子類,原子類都是基于 sun.misc.Unsafe  實現的。

  • CPU 為了解決并發問題,提供了 CAS 指令,全稱 Compare And Swap,即比較并交互

  • CAS 指令需要 3 個參數,變量、比較值、新值。當變量的當前值與比較值相等時,才把變量更新為新值

  • CAS 是一條 CPU 指令,由 CPU 硬件級別上保證原子性

java.util.concurrent.atomic  包中的原子分為:原子性基本數據類型、原子性對象引用類型、原子性數組、原子性對象屬性更新器和原子性累加器

原子性基本數據類型:AtomicBoolean、AtomicInteger、AtomicLong

原子性對象引用類型:AtomicReference、AtomicStampedReference、AtomicMarkableReference

原子性數組:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

原子性對象屬性更新:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

原子性累加器:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder

修改我們之前測試原子性問題的類,使用 AtomicInteger 的簡單例子

package constxiong.concurrency.a026;  import java.util.concurrent.atomic.AtomicInteger;  /**  * 測試 原子類 AtomicInteger  *   * @author ConstXiong  */ public class TestAtomicInteger {   // 計數變量  static volatile AtomicInteger count = new AtomicInteger(0);   public static void main(String[] args) throws InterruptedException {  // 線程 1 給 count 加 10000  Thread t1 = new Thread(() -> {  for (int j = 0; j <10000; j++) {  count.incrementAndGet();  }  System.out.println("thread t1 count 加 10000 結束");  });   // 線程 2 給 count 加 10000  Thread t2 = new Thread(() -> {  for (int j = 0; j <10000; j++) {  count.incrementAndGet();  }  System.out.println("thread t2 count 加 10000 結束");  });   // 啟動線程 1  t1.start();  // 啟動線程 2  t2.start();   // 等待線程 1 執行完成  t1.join();  // 等待線程 2 執行完成  t2.join();   // 打印 count 變量  System.out.println(count.get());  }  }

打印結果如預期

thread t2 count 加 10000 結束 thread t1 count 加 10000 結束 20000

二、線程本地存儲

  • java.lang.ThreadLocal 類用于線程本地化存儲。

  • 線程本地化存儲,就是為每一個線程創建一個變量,只有本線程可以在該變量中查看和修改值。

  • 典型的使用例子就是,spring 在處理數據庫事務問題的時候,就用了 ThreadLocal 為每個線程存儲了各自的數據庫連接  Connection。

  • 使用 ThreadLocal 要注意,在不使用該變量的時候,一定要調用 remove() 方法移除變量,否則可能造成內存泄漏的問題。

示例

package constxiong.concurrency.a026;  /**  * 測試 原子類 AtomicInteger  *   * @author ConstXiong  */ public class TestThreadLocal {   // 線程本地存儲變量  private static final ThreadLocal<Integer> THREAD_LOCAL_NUM = new ThreadLocal<Integer>() {  @Override  protected Integer initialValue() {//初始值  return 0;  }  };   public static void main(String[] args) {  for (int i = 0; i <3; i++) {// 啟動三個線程  Thread t = new Thread() {  @Override  public void run() {  add10ByThreadLocal();  }  };  t.start();  }  }   /**  * 線程本地存儲變量加 5  */  private static void add10ByThreadLocal() {  try {  for (int i = 0; i <5; i++) {  Integer n = THREAD_LOCAL_NUM.get();  n += 1;  THREAD_LOCAL_NUM.set(n);  System.out.println(Thread.currentThread().getName() + " : ThreadLocal num=" + n);  }  } finally {  THREAD_LOCAL_NUM.remove();// 將變量移除  }  } }

每個線程最后一個值都打印到了 5

Thread-0 : ThreadLocal num=1 Thread-2 : ThreadLocal num=1 Thread-1 : ThreadLocal num=1 Thread-2 : ThreadLocal num=2 Thread-0 : ThreadLocal num=2 Thread-2 : ThreadLocal num=3 Thread-0 : ThreadLocal num=3 Thread-1 : ThreadLocal num=2 Thread-0 : ThreadLocal num=4 Thread-2 : ThreadLocal num=4 Thread-0 : ThreadLocal num=5 Thread-1 : ThreadLocal num=3 Thread-2 : ThreadLocal num=5 Thread-1 : ThreadLocal num=4 Thread-1 : ThreadLocal num=5

三、copy-on-write

根據英文名稱可以看出,需要寫時復制,體現的是一種延時策略。

Java 中的 copy-on-write 容器包括:CopyOnWriteArrayList、CopyOnWriteArraySet。

涉及到數組的全量復制,所以也比較耗內存,在寫少的情況下使用比較適合。

簡單的 CopyOnWriteArrayList 的示例,這里只是說明 CopyOnWriteArrayList  怎么用,并且是線程安全的。這個場景并不適合使用 CopyOnWriteArrayList,因為寫多讀少。

package constxiong.concurrency.a026;  import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList;  /**  * 測試 copy-on-write  * @author ConstXiong  */ public class TestCopyOnWrite {   private static final Random R = new Random();    private static CopyOnWriteArrayList<Integer> cowList = new CopyOnWriteArrayList<Integer>(); // private static ArrayList<Integer> cowList = new ArrayList<Integer>();    public static void main(String[] args) throws InterruptedException {  List<Thread> threadList = new ArrayList<Thread>();  //啟動 1000 個線程,向 cowList 添加 5 個隨機整數  for (int i = 0; i <1000; i++) {  Thread t = new Thread(() -> {  for (int j = 0; j <5; j++) {  //休眠 10 毫秒,讓線程同時向 cowList 添加整數,引出并發問題  try {  Thread.sleep(10);  } catch (InterruptedException e) {  e.printStackTrace();  }  cowList.add(R.nextInt(100));  }  }) ;  t.start();  threadList.add(t);  }    for (Thread t : threadList) {  t.join();  }  System.out.println(cowList.size());  } }

打印結果

5000

如果把

private static CopyOnWriteArrayList<Integer> cowList = new CopyOnWriteArrayList<Integer>();

改為

private static ArrayList<Integer> cowList = new ArrayList<Integer>();

打印結果就是小于 5000 的整數了

“如何使用Java中無鎖技術”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

油尖旺区| 禹城市| 北宁市| 宾川县| 古浪县| 察雅县| 施秉县| 郧西县| 于都县| 北京市| 邢台县| 高唐县| 金塔县| 安丘市| 红原县| 泰安市| 桑日县| 阜南县| 琼结县| 刚察县| 修水县| 金秀| 上林县| 太湖县| 华池县| 读书| 灯塔市| 安泽县| 阿克陶县| 大同市| 永定县| 嘉兴市| 阿拉善右旗| 海口市| 扶沟县| 宁明县| 微山县| 洪洞县| 孟州市| 拜泉县| 石泉县|