Javaマルチスレッドの高度な並行データ構造

Javaマルチスレッドの高度な並行データ構造

  • 並行データ構造
    • 一般的に使用されるデータ構造はスレッドセーフではありません
      • ArrayList / HashMap / HashSet非同期
      • 複数のスレッドが同時に単独で書き込みを行うと、例外またはデータエラーがスローされる場合がある
    • 従来のベクター/ HashTableおよびその他の同期されたデータコレクションのパフォーマンスが低い
    • 並行データ構造:データの追加または削除
      • コレクションのブロック:コレクションが空またはいっぱいの場合、待機します
      • ノンブロッキングコレクション:コレクションが空またはいっぱいの場合、待機せず、nullまたは例外を返します。
    • リスト
      • 同期セキュリティをベクトル化し、書き込みを増やし、読み取りを減らし、効率を低下させる
      • ArrayListは安全ではありません
      • 同期に基づく同期リスト(リストリスト)メソッドは、リストをスレッドセーフにし、効率を低下させます
      • CopyOnWriteArrayList(JDK5はコピーメカニズムに基づいた同時実行リストクラスを提供します)、ノンブロッキング、より多くの読み取りと少ない書き込みに適しています。つまり、データを入力した後、ほとんどの操作が読み取られてトラバースされます。効率がよく、複数のスレッドでの使用に適しています。
          package thread0418;
      
          import java.time.LocalDateTime;
          import java.util.ArrayList;
          import java.util.Collections;
          import java.util.List;
          import java.util.concurrent.CopyOnWriteArrayList;
      
          /**
           * 并发数据结构对比
           */
          public class ThreadListDemo1 {
              public static void main(String[] args) throws InterruptedException {
                  // 线程不安全
                  List<String> unsafeList = new ArrayList<String>();
                  // 线程安全 将一个不安全的转成安全的
                  List<String> safeList1 = Collections.synchronizedList(new ArrayList<String>());
                  // 线程安全
                  CopyOnWriteArrayList<String> safeList2 = new CopyOnWriteArrayList<String>();
      
                  ListThread111 t1 = new ListThread111(unsafeList);
                  ListThread111 t2 = new ListThread111(safeList1);
                  ListThread111 t3 = new ListThread111(safeList2);
      
                  // 分别启动十个线程, 运行测试
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t1, String.valueOf(i));
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t2, String.valueOf(i));
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t3, String.valueOf(i));
                      t.start();
                  }
      
                  // 等待子线程执行完
                  Thread.sleep(2000);
      
                  System.out.println(LocalDateTime.now() + " => " + t1.list.size());
                  System.out.println(LocalDateTime.now() + " => " + t2.list.size());
                  System.out.println(LocalDateTime.now() + " => " + t3.list.size());
      
                  // 输出list中的值
                  System.out.println(LocalDateTime.now() + " => " + "unsafeList:");
                  for (String s : t1.list) {
                      if (s == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(s + " ");
                      }
                  }
                  System.out.println();
      
                  System.out.println(LocalDateTime.now() + " => " + "safeList1: ");
                  for (String s : t2.list) {
                      if (s == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(s + " ");
                      }
                  }
                  System.out.println();
      
                  System.out.println(LocalDateTime.now() + " => " + "safeList2: ");
                  for (String s : t3.list) {
                      if (s == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(s + " ");
                      }
                  }
      
      
              }
          }
      
          class ListThread111 implements Runnable {
              public List<String> list;
      
              public ListThread111(List<String> list) {
                  this.list = list;
              }
      
              @Override
              public void run() {
                  int i = 0;
                  while (i < 10) {
                      try {
                          Thread.sleep(10);
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                      // 把当前线程名字加到 list 中
                      list.add(Thread.currentThread().getName());
                      i++;
                  }
              }
          }
      
    • セットする
      • HashSetは安全ではありません
      • 同期された低効率に基づくCollections.synchronizedSet(セットセット)
      • CopyOnWriteArraySet(JDK5が提供するCopyOnWriteArrayListに基づく実装)、非ブロッキング、読み取りと書き込みを少なくするのに適しており、効率がよく、マルチスレッドの使用に適しています。
          package thread0418;
      
          import java.time.LocalDateTime;
          import java.util.Collections;
          import java.util.HashSet;
          import java.util.Set;
          import java.util.concurrent.CopyOnWriteArraySet;
      
          public class ThreadSetDemo1 {
              public static void main(String[] args) throws InterruptedException {
                  // 线程不安全
                  Set<String> unsafeSet = new HashSet<String>();
                  // 线程安全
                  Set<String> safeSet1 = Collections.synchronizedSet(new HashSet<>());
                  // 线程安全
                  CopyOnWriteArraySet<String> safeSet2 = new CopyOnWriteArraySet<>();
      
                  SetThread111 t1 = new SetThread111(unsafeSet);
                  SetThread111 t2 = new SetThread111(safeSet1);
                  SetThread111 t3 = new SetThread111(safeSet2);
      
                  // 分别启动十个线程, 运行测试
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t1, String.valueOf(i));
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t2, String.valueOf(i));
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t3, String.valueOf(i));
                      t.start();
                  }
      
                  // 等待子线程执行完成
                  Thread.sleep(2000);
      
      
                  System.out.println(LocalDateTime.now() + " => " + t1.set.size());
                  System.out.println(LocalDateTime.now() + " => " + t2.set.size());
                  System.out.println(LocalDateTime.now() + " => " + t3.set.size());
      
                  // 输出 Set 中的值
                  System.out.println(LocalDateTime.now() + " => " + "unsafeSet: ");
                  for (String ele : t1.set) {
                      if (ele == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(ele + " ");
                      }
                  }
                  System.out.println();
                  System.out.println(LocalDateTime.now() + " => " + "safeSet1: ");
                  for (String ele : t2.set) {
                      if (ele == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(ele + " ");
                      }
                  }
                  System.out.println();
                  System.out.println(LocalDateTime.now() + " => " + "safeSet2: ");
                  for (String ele : t3.set) {
                      if (ele == null) {
                          System.out.print("null ");
                      } else {
                          System.out.print(ele + " ");
                      }
                  }
              }
          }
      
          class SetThread111 implements Runnable {
              public Set<String> set;
      
              public SetThread111(Set<String> set) {
                  this.set = set;
              }
      
              @Override
              public void run() {
                  int i = 0;
                  while (i < 10) {
                      try {
                          Thread.sleep(10);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      // 把当前线程名称加入 set里
                      set.add(Thread.currentThread().getName() + i);
                      i++;
                  }
              }
          }
      
    • 地図
      • ハッシュテーブルの同期セキュリティ、書き込みと読み取りが少ない、効率が悪い
      • HashMapは安全ではありません
      • 同期された低効率に基づくCollections.synchronizedMap(マップマップ)
      • ConcurrentHashMap読み取りと書き込みが少なく、非ブロッキング
          package thread0418;
      
          import java.time.LocalDateTime;
          import java.util.Collections;
          import java.util.HashMap;
          import java.util.Iterator;
          import java.util.Map;
          import java.util.concurrent.ConcurrentHashMap;
      
          public class ThreadMapDemo1 {
              public static void main(String[] args) throws InterruptedException {
                  // 线程不安全
                  MapThread111 t1 = new MapThread111(new HashMap<>());
                  // 线程安全
                  MapThread111 t2 = new MapThread111(Collections.synchronizedMap(new HashMap<>()));
                  // 线程安全
                  MapThread111 t3 = new MapThread111(new ConcurrentHashMap<>());
      
                  // 分别启动十个线程, 运行测试
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t1);
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t2);
                      t.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread t = new Thread(t3);
                      t.start();
                  }
      
                  // 等待子线程执行完
                  Thread.sleep(2000);
                  System.out.println(LocalDateTime.now() + " => " + t1.map.size());
                  System.out.println(LocalDateTime.now() + " => " + t2.map.size());
                  System.out.println(LocalDateTime.now() + " => " + t3.map.size());
      
                  // 输出 map 中的值
                  System.out.println(LocalDateTime.now() + " => " + "unsafeMap:");
                  Iterator<Map.Entry<Integer, String>> iterator = t1.map.entrySet().iterator();
                  while (iterator.hasNext()) {
                      Map.Entry<Integer, String> entry = iterator.next();
                      System.out.print(entry.getKey() + ":" + entry.getValue() + "  ");
                  }
                  System.out.println();
      
                  System.out.println(LocalDateTime.now() + " => " + "safeMap:");
                  iterator = t2.map.entrySet().iterator();
                  while (iterator.hasNext()) {
                      Map.Entry<Integer, String> entry = iterator.next();
                      System.out.print(entry.getKey() + ":" + entry.getValue() + "  ");
                  }
                  System.out.println();
      
                  System.out.println(LocalDateTime.now() + " => " + "safeMap2:");
                  iterator = t3.map.entrySet().iterator();
                  while (iterator.hasNext()) {
                      Map.Entry<Integer, String> entry = iterator.next();
                      System.out.print(entry.getKey() + ":" + entry.getValue() + "  ");
                  }
                  System.out.println();
                  System.out.println(LocalDateTime.now() + " => " + "mapThread1.map.size()" + t1.map.size());
                  System.out.println(LocalDateTime.now() + " => " + "mapThread2.map.size()" + t2.map.size());
                  System.out.println(LocalDateTime.now() + " => " + "mapThread3.map.size()" + t3.map.size());
      
      
              }
          }
      
          class MapThread111 implements Runnable {
              public Map<Integer, String> map;
      
              public MapThread111(Map<Integer, String> map) {
                  this.map = map;
              }
      
              @Override
              public void run() {
                  int i = 0;
                  while (i < 100) {
                      try {
                          Thread.sleep(10);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      // 把当前线程名称放入map中
                      map.put(++i, Thread.currentThread().getName());
                  }
              }
          }
      
    • Queue(一方向キュー)およびDeque(双方向キュー)(JDK1.5)
      • ConcurrentLinkedQueueノンブロッキング
      • ArrayBlockingQueue / LinkedBlockingQueue遮断
          package thread0418;
      
          import java.time.LocalDateTime;
          import java.util.ArrayDeque;
          import java.util.Queue;
          import java.util.concurrent.ArrayBlockingQueue;
          import java.util.concurrent.ConcurrentLinkedDeque;
      
          public class ThreadQueueDemo1 {
              public static void main(String[] args) throws InterruptedException {
                  // 线程不安全
                  QueueThread111 t1 = new QueueThread111(new ArrayDeque<>());
                  // 线程安全
                  QueueThread111 t2 = new QueueThread111(new ConcurrentLinkedDeque<>());
                  QueueThread111 t3 = new QueueThread111(new ArrayBlockingQueue<>(100));
      
                  for (int i = 0; i < 10; i++) {
                      Thread thread = new Thread(t1, String.valueOf(i));
                      thread.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread thread = new Thread(t2, String.valueOf(i));
                      thread.start();
                  }
                  for (int i = 0; i < 10; i++) {
                      Thread thread = new Thread(t3, String.valueOf(i));
                      thread.start();
                  }
      
                  // 等待子线程执行完
                  Thread.sleep(2000);
      
                  System.out.println(LocalDateTime.now() + " => " + t1.queue.size());
                  System.out.println(LocalDateTime.now() + " => " + t2.queue.size());
                  System.out.println(LocalDateTime.now() + " => " + t3.queue.size());
      
                  // 输出 Queue 中的值
                  System.out.println("unsafeQueue: ");
                  for (String s : t1.queue) {
                      System.out.print(s + " ");
                  }
                  System.out.println();
                  System.out.println("safeQueue1: ");
                  for (String s : t2.queue) {
                      System.out.print(s + " ");
                  }
                  System.out.println();
                  System.out.println("safeQueue2: ");
                  for (String s : t3.queue) {
                      System.out.print(s + " ");
                  }
              }
          }
      
          class QueueThread111 implements Runnable {
              public Queue<String> queue;
      
              public QueueThread111(Queue<String> queue) {
                  this.queue = queue;
              }
      
              @Override
              public void run() {
                  int i = 0;
                  while (i < 10) {
                      i++;
                      try {
                          Thread.sleep(10);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      // 把当前线程名称加入list中
                      queue.add(Thread.currentThread().getName());
                  }
              }
          }
      
  • まとめ
    • データ構造の同時書き込みの問題を理解する
    • ビジネス特性に従って、正しい並行データ構造を使用します

おすすめ

転載: www.cnblogs.com/sweetXiaoma/p/12737697.html