iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 9
0
Software Development

30 天介紹 Java 的 Thread系列 第 9

Day9 介紹使用 CopyOnWriteArrayList

當我們需要一邊讀 List 內容並且另外一個 Thread 需要增加內容到 List 內,如果使用 ArrayList 的方式去做的話會有問題,Sample Code 如下:

public class ThreadExample implements Runnable {
  private List<String> list;

  public ThreadExample(List<String> list) {
    this.list = list;
  }

  @Override
  public void run() {
    try {
      for (int i = 0; i < 10; i++) {
        list.add("b" + i);
      }
    } catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

當執行 Thread 的程式時會將資料 add 到 ArrayList 裡

import java.util.ArrayList;
import java.util.List;

public class Main {

  public static void main(String[] args) {
    try {
      List<String> list = new ArrayList<String>();
      list.add("a1");
      list.add("a2");
      list.add("a3");
      list.add("a4");
      list.add("a5");
      list.add("a6");

      Thread thread = new Thread(new ThreadExample(list));
      thread.start();

      for(String s: list) {
        System.out.println(s);
      }
    } catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

主程式在啟動執行緒時會一邊讀資料一邊寫資料,這樣有可能在執行這支程式的時侯發生 Exception,如下:

Exception in thread "main" java.lang.RuntimeException: java.util.ConcurrentModificationException
	at com.company.Main.main(Main.java:24)
Caused by: java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at com.company.Main.main(Main.java:20)
a1
a2
a3
a4
a5
a6

這個 Exception 有可能要執行非常多次才有可能會發生。主要發生 Exception 的原因是 ArrayList 不能同時去讀寫這樣就有可能會出錯誤。

要解決這個問題可以使用前面幾天介紹的 synchronized 的方式去解,但是用這個方式會造成執行速度變慢,在寫的時侯就不能讀或是在讀的時侯不能寫。因此使用這個方式去做對執行的效能不好。因此可以改用另外一種方式, CopyOnWriteArrayList 就是再讀的時侯複製出一份相同的資料內容,這樣就避免掉了,同時讀寫一個 List 遇到的問題,Sample code 如下:

import java.util.concurrent.CopyOnWriteArrayList;

public class Main {

  public static void main(String[] args) {
    try {
      final CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
      list.add("a1");
      list.add("a2");
      list.add("a3");
      list.add("a4");
      list.add("a5");
      list.add("a6");

      Thread thread = new Thread(new ThreadExample(list));
      thread.start();

      for(String s: list) {
        System.out.println(s);
      }
    } catch(Exception e) {
      throw new RuntimeException(e);
    }
  }
}

把 ArrayList 修改成 CopyOnWriteArrayList 就可以解決同時讀寫 List 的問題。

使用 CopyOnWriteArrayList 適合的使用情境是當資料讀取的次數比寫入的次數還多的時侯,因為寫入的資料不多 copy 的大小也不會太大,所以在此情況下執行的效能會較好。


上一篇
Day8 介紹 Semaphore Class
下一篇
Day 10 介紹 LinkedBlockingQueue 類別 (一)
系列文
30 天介紹 Java 的 Thread30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言