在單執行緒應用中,通常會採取new ArrayList(),指定一個List集合,用來存放可重複的資料。
但在多執行緒下,往往會出現意想不到的問題,程式碼如下所示:
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { // 创建list集合 //List<String> lists = Arrays.asList("1", "2", "3"); // 不安全 List<String> lists = new ArrayList<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
多執行緒操作同一集合物件訊息,往往會出現java.util.ConcurrentModificationException異常報錯資訊.
在java語言中,提供了一個新的List集合,java.util.Vector類,具體看下列程式碼:
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { // 创建list集合 //List<String> lists = Arrays.asList("1", "2", "3"); // 不安全 //List<String> lists = new ArrayList<>(); List<String> lists = new Vector<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
不會出現java.util.ConcurrentModificationException報錯訊息。
為什麼能保證資料的安全操作?
採取了 synchronized 針對方法執行呼叫者加鎖,保證add操作的多執行緒安全性!
在JUC套件下,提供以下幾種建立安全集合的方式。
方式一:Collections.synchronizedList(new ArrayList<>());
import java.util.*; public class ListTest { public static void main(String[] args) throws InterruptedException { List<String> lists = Collections.synchronizedList(new ArrayList<>()); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
查看底層原始碼實作邏輯
#判斷傳入的list 集合類型,判斷類型是否為java.util.RandomAccess,如果是則採取java.util.Collections.SynchronizedRandomAccessList建構集合,如果不是則採取java.util.Collections.SynchronizedList建構集合。
源碼中對應的add操作邏輯如下所示:
#採取synchronized同步程式碼區塊的方式,資料的add操作實現加鎖!
方式二:new CopyOnWriteArrayList();
import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; public class ListTest { public static void main(String[] args) throws InterruptedException { List<String> lists = new CopyOnWriteArrayList<>(); // 开启十个线程增加数据 for (int i = 1; i <= 40; i++) { new Thread(()->{ lists.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(Thread.currentThread().getName()+"=="+lists); },String.valueOf(i)).start(); } } }
原始碼中的介紹如下:
#顯而易見,其邏輯如下所示:
#呼叫add方法後,拿到java.util.concurrent.locks .ReentrantLock物件資訊。
呼叫 lock.lock() 拿到鎖定!
將原數組物件copy操作,並建立原始數組大小 1的新數組。
將新資料放入新陣列中。
任何操作finally,都進行鎖定的釋放!
JUC套件下的Lock操作,都比synchronized效能更好!
以上是Java JUC怎麼操作List安全類別的集合的詳細內容。更多資訊請關注PHP中文網其他相關文章!