您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關java高并發同步容器指的是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
在java中同步容器主要包括兩類:
ArrayList -> Vector,Stack; HashMap -> HashTable(key,value不能為null)
Collections.synchronizedXXX(List, Set, Map)
Vector實現了List接口,實際上就是一個數組。與ArrayList非常類似。但是Vector中的所有方法都是使用synchronized方法修飾的方法,進行了同步的措施。因此在多線程環境下使用ArrayList對象時,如果被多個線程共享使用可以換成同步的Vector,這樣的話線程安全型會更好一些(而不是完全線程安全的)。
@Slf4j @ThreadSafe public class VectorExample1 { // 請求總數 public static int clientTotal = 5000; // 同時并發執行的線程數 public static int threadTotal = 200; private static List<Integer> list = new Vector<>(); public static void main(String[] args) throws InterruptedException { //線程池 ExecutorService executorService = Executors.newCachedThreadPool(); //定義信號量 final Semaphore semaphore = new Semaphore(threadTotal); //定義計數器 final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for(int i = 0; i < clientTotal; i++) { final int count = i; executorService.execute(() ->{ try { semaphore.acquire(); update(count); semaphore.release(); } catch (InterruptedException e) { log.error("exception", e); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); log.info("size:{}",list.size()) ; } public static void update(int i) { list.add(i); } }
這樣輸出的結果就是預期的結果。
@NotThreadSafe public class VectorExample2 { private static Vector<Integer> vector = new Vector<>(); public static void main(String[] args) { while (true){ for (int i = 0;i < 10;i++) { vector.add(i); } Thread thread1 = new Thread(){ @Override public void run() { for (int i = 0;i < vector.size();i++) { vector.remove(i); } } }; Thread thread2 = new Thread(){ @Override public void run() { for (int i = 0;i < vector.size();i++) { vector.get(i); } } }; thread1.start(); thread2.start(); } } }
運行,拋出異常:
Exception in thread "Thread-611" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 5 at java.util.Vector.get(Vector.java:748) at com.vincent.example.syncContainer.VectorExample2$2.run(VectorExample2.java:25) Exception in thread "Thread-1759" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 21 at java.util.Vector.get(Vector.java:748) at com.vincent.example.syncContainer.VectorExample2$2.run(VectorExample2.java:25)
原因:get發生越界肯定是remove方法引起的,vector雖然能保證同一時刻只能有一個線程能訪問他,但是不排除有這種可能:當某個線程某個時刻執行到int i = 0;i < vector.size()時,vector.size()返回10,i=9;而另外一個線程正好將i=9的vector移除掉了,這時get方法想調用i=9的元素就會出現數組越界的異常。
這個例子演示了兩個同步容器的兩個同步方法因為操作順序的差異,在不同線程里面可能會觸發線程不安全的問題。因此為了保證線程安全,必須在方法調用端做一些額外的同步措施才可以。在使用同步容器時并不是在所有場合下都是線程安全的。
Stack中的方法也使用了synchronized修飾了,實際上Stack類繼承了Vector類。
HashTable實現了Map接口,與HashMap很相似,但是HashTable進行了同步處理,方法也是使用了synchronized進行了修飾。但是在使用HashTable時一定要注意key和value是不能為null的。
將新建ArrayList、HashSet、HashMap對象由Collections產生:
private static List<Integer> list = Collections.synchronizedList(new ArrayList<>()); private static Set<Integer> set = Collections.synchronizedSet(new HashSet<>()); private static Map<Integer, Integer> map = Collections.synchronizedMap(new HashMap<>());
public class VectorExample3 { //Exception in thread "main" java.util.ConcurrentModificationException private static void test1(Vector<Integer> v1){ //foreach for(Integer i: v1){ if(i.equals(3)){ v1.remove(i); } } } //Exception in thread "main" java.util.ConcurrentModificationException private static void test2(Vector<Integer> v1){ //iterator Iterator<Integer> integerIterator = v1.iterator(); while (integerIterator.hasNext()) { Integer i = integerIterator.next(); if(i.equals(3)){ v1.remove(i); } } } // success private static void test3(Vector<Integer> v1){ for(int i = 0; i < v1.size(); i++) { if(v1.equals(3)){ v1.remove(i); } } } public static void main(String[] args) { Vector<Integer> vector = new Vector<>(); vector.add(1); vector.add(2); vector.add(3); test1(vector); } }
如果使用了Foreach或者迭代器來循環我們的集合時,盡量不要在循環中做集合的刪除操作,如果要做remove操作時,建議在遍歷的過程中發現需要刪除的值然后做一個標記,在遍歷結束后在執行相應的remove操作。在多線程情況下出現異常的情況會更大。
關于java高并發同步容器指的是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。