轉:java多線程--同步容器

来源:http://www.cnblogs.com/lcngu/archive/2016/02/28/5224808.html
-Advertisement-
Play Games

java同步容器 在Java的集合容器框架中,主要有四大類別:List、Set、Queue、Map。List、Set、Queue介面分別繼承了Collection介面,Map本身是一個介面。註意Collection和Map是一個頂層介面,而List、Set、Queue則繼承了Collection介面


  • java同步容器

  在Java的集合容器框架中,主要有四大類別:List、Set、Queue、Map。List、Set、Queue介面分別繼承了Collection介面,Map本身是一個介面。註意Collection和Map是一個頂層介面,而List、Set、Queue則繼承了Collection介面,分別代表數組、集合和隊列這三大類容器。像ArrayList、LinkedList、HashMap這些容器都是非線程安全的。因此,在編寫程式時,必須要求程式員手動地在任何訪問到這些容器的地方進行同步處理,這樣導致在使用這些容器的時候非常地不方便。

  • java中的同步容器

  1)Vector、Stack、HashTable  

  Vector實現了List介面,Vector實際上就是一個數組,和ArrayList類似,但是Vector中的方法都是synchronized方法,即進行了同步措施。

  Stack也是一個同步容器,它的方法也用synchronized進行了同步,它實際上是繼承於Vector類。

  HashTable實現了Map介面,它和HashMap很相似,但是HashTable進行了同步處理,而HashMap沒有。

  2)Collections類中提供的靜態工廠方法創建的類:

  Collections類是一個工具提供類,註意,它和Collection不同,Collection是一個頂層的介面。在Collections類中提供了大量的方法,比如對集合或者容器進行排序、查找等操作。最重要的是,在它裡面提供了幾個靜態工廠方法來創建同步容器類。

  • 同步容器缺陷

  從同步容器的具體實現源碼可知,同步容器中的方法採用了synchronized進行了同步,那麼很顯然,這必然會影響到執行性能,另外,同步容器不一定是真正地完全線程安全的,還需要添加額外的同步措施。

例如:

 1 public class Test {
 2     static Vector<Integer> vector = new Vector<Integer>();
 3     public static void main(String[] args) throws InterruptedException {
 4         while(true) {
 5             for(int i=0;i<10;i++)
 6                 vector.add(i);
 7             Thread thread1 = new Thread(){
 8                 public void run() {
 9                     for(int i=0;i<vector.size();i++)
10                         vector.remove(i);
11                 };
12             };
13             Thread thread2 = new Thread(){
14                 public void run() {
15                     for(int i=0;i<vector.size();i++)
16                         vector.get(i);
17                 };
18             };
19             thread1.start();
20             thread2.start();
21             while(Thread.activeCount()>10)   {
22                  
23             }
24         }
25     }
26 }
View Code
 1 public class Test {
 2     static Vector<Integer> vector = new Vector<Integer>();
 3     public static void main(String[] args) throws InterruptedException {
 4         while(true) {
 5             for(int i=0;i<10;i++)
 6                 vector.add(i);
 7             Thread thread1 = new Thread(){
 8                 public void run() {
 9                     synchronized (Test.class) {   //進行額外的同步
10                         for(int i=0;i<vector.size();i++)
11                             vector.remove(i);
12                     }
13                 };
14             };
15             Thread thread2 = new Thread(){
16                 public void run() {
17                     synchronized (Test.class) {
18                         for(int i=0;i<vector.size();i++)
19                             vector.get(i);
20                     }
21                 };
22             };
23             thread1.start();
24             thread2.start();
25             while(Thread.activeCount()>10)   {
26                  
27             }
28         }
29     }
30 }
View Code
  • ConcurrentModificationException異常

  在對容器併發地進行迭代修改時,會報ConcurrentModificationException異常。

 1 public class Test {
 2     public static void main(String[] args)  {
 3         ArrayList<Integer> list = new ArrayList<Integer>();
 4         list.add(2);
 5         Iterator<Integer> iterator = list.iterator();
 6         while(iterator.hasNext()){
 7             Integer integer = iterator.next();
 8             if(integer==2)
 9                 list.remove(integer);
10         }
11     }
12 }

  這樣會報ConcurrentModificationException異常,我們定位到源碼查看。

 1 private class Itr implements Iterator<E> {
 2         int cursor;       // index of next element to return
 3         int lastRet = -1; // index of last element returned; -1 if no such
 4         int expectedModCount = modCount;
 5 
 6         public boolean hasNext() {
 7             return cursor != size;
 8         }
 9 
10         @SuppressWarnings("unchecked")
11         public E next() {
12             checkForComodification();
13             int i = cursor;
14             if (i >= size)
15                 throw new NoSuchElementException();
16             Object[] elementData = ArrayList.this.elementData;
17             if (i >= elementData.length)
18                 throw new ConcurrentModificationException();
19             cursor = i + 1;
20             return (E) elementData[lastRet = i];
21         }
22 
23         public void remove() {
24             if (lastRet < 0)
25                 throw new IllegalStateException();
26             checkForComodification();
27 
28             try {
29                 ArrayList.this.remove(lastRet);
30                 cursor = lastRet;
31                 lastRet = -1;
32                 expectedModCount = modCount;
33             } catch (IndexOutOfBoundsException ex) {
34                 throw new ConcurrentModificationException();
35             }
36         }
37 
38         final void checkForComodification() {
39             if (modCount != expectedModCount)
40                 throw new ConcurrentModificationException();
41         }
42  }
View Code

  首先我們看一下它的幾個成員變數:

  cursor:表示下一個要訪問的元素的索引,從next()方法的具體實現就可看出

  lastRet:表示上一個訪問的元素的索引

  expectedModCount:表示對ArrayList修改次數的期望值,它的初始值為modCount。

  modCount是AbstractList類中的一個成員變數,該值表示對List的修改次數,查看ArrayList的add()和remove()方法就可以發現,每次調用add()方法或者remove()方法等就會對modCount進行加1操作。

  因為modCount的修改,而導致expectedModCount和modCount不相等,即checkForComodification()拋異常導致。

  解決方法:

  1:單線程環境下:iterator.remove();

  2:多線程環境下:

    1)在使用iterator迭代的時候使用synchronized或者Lock進行同步;

    2)使用併發容器CopyOnWriteArrayList代替ArrayList和Vector。

  • java5新增的併發類

  大家都知道HashMap是非線程安全的,Hashtable是線程安全的,但是由於Hashtable是採用synchronized進行同步,相當於所有線程進行讀寫時都去競爭一把鎖,導致效率非常低下。ConcurrentHashMap可以做到讀取數據不加鎖,並且其內部的結構可以讓其在進行寫操作的時候能夠將鎖的粒度保持地儘量地小,不用對整個ConcurrentHashMap加鎖。  

  CopyOnWrite容器即寫時複製的容器。通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,複製出一個新的容器,然後新的容器里添加元素,添加完元素之後,再將原容器的引用指向新的容器。這樣做的好處是我們可以對CopyOnWrite容器進行併發的讀,而不需要加鎖,因為當前容器不會添加任何元素。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。

  CopyOnWrite容器有很多優點,但是同時也存在兩個問題,即記憶體占用問題和數據一致性問題:CopyOnWrite容器只能保證數據的最終一致性,不能保證數據的實時一致性。所以如果你希望寫入的的數據,馬上能讀到,請不要使用CopyOnWrite容器。

  參考博客:

  http://home.cnblogs.com/u/dolphin0520/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 通過 ajax() 與 一般處理程式,請求資料庫數據,實現界面無刷新。 Jquery ajax 請求參數詳細說明 http://www.w3school.com.cn/jquery/ajax_ajax.asp 代碼: 1 <!DOCTYPE html> 2 3 <html xmlns="http:/
  • 內容轉自 http://blog.csdn.net/pasic/article/details/7110134 Asp.net MVC中Controller返回值類型在mvc中所有的controller類都必須使用"Controller"尾碼來命名並且對Action也有一定的要求: 必須是一個pub
  • 對junit單元測試的報告:類似這樣的結果 ------------------------------------------------------- T E S T S ------------------------------------------------------- Runnin
  • 玩轉Windows服務系列彙總 [創建Windows服務][1] [Debug、Release版本的註冊和卸載及其原理][2] [無COM介面Windows服務啟動失敗原因及解決方案][3] [服務運行、停止流程淺析][4] [Windows服務小技巧][5] [命令行管理Windows服務][6]
  • Hadoop、Redis、Memcached、MongoDB、Spark、Storm、雲計算、R語言、機器學習、Nginx、Linux、MySQL、Java EE、.NET、PHP Memcached 視頻教程 大數據 高性能 集群 NoSQL 安裝 命令 使用
  • Hadoop、Redis、Memcached、MongoDB、Spark、Storm、雲計算、R語言、機器學習、Nginx、Linux、MySQL、Java EE、.NET、PHP MongoDB 權威 實戰 入門應用 視頻教程 大數據 高性能 集群 NoSQL
  • Hadoop、Redis、Memcached、MongoDB、Spark、Storm、雲計算、R語言、機器學習、Nginx、Linux、MySQL、Java EE、.NET、PHP R語言 視頻教程 實戰 數據分析 數據挖掘 入門編程 培訓 核心技術
  • 1.什麼叫做會話控制 允許伺服器根據客戶端做出的連續請求。 2.為什麼需要會話控制? 因為當你打開一個網站,並想訪問該網站的其他頁面的時候,如果沒有會話控制,當跳轉到其他頁面的 時候,就需要再次輸入賬戶和密碼。 3.Cookie的原理和作用 將客戶端的簡單信息保存在個人PC中,其他程式獲取PC的Co
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...