【java項目實戰】ThreadLocal封裝Connection,實現同一線程共用資源

來源:互聯網
上載者:User

標籤:set   多線程   art   fonts   針對   dbcc   try   key   線程   

       安全執行緒一直是程式員們關注的焦點。多線程也一直是比較讓人頭疼的話題,想必大家以前也遇到過各種各種的問題。我就不再累述了。當然,解決方案也有非常多,這篇博文給大家提供一種非常好的解決安全執行緒問題的思路。

 

      首先。我們先簡單的認識一下ThreadLocal,之後是執行個體+解析,最後一句話總結。


1、認識一下ThreaLocal


       認識ThreadLocal必需要通過api文檔,不只具有說服力,並且它會給你更加全面的解釋。以下我我給大家從api文檔上截取一張圖,並標出來了七點需要重點理解的內容,執行個體過後的解析也是重點解釋這七部分。




      對於上面的內容。不理解沒有關係,我們通過以下的執行個體加深一下理解,執行個體之後我會給大家一個更加深入的解釋。


2、ThreaLocal封裝Connection執行個體+解析


       以下的代碼僅僅是ThreaLocal封裝Connection的核心代碼,對於多餘的內容成功避開就好,而且有一部分代碼是“dom4j解析xml檔案。串連資料庫”的內容,很適合剛開始學習的人,如有須要,請您移駕到此。


package com.bjpowernode.drp.util;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;/** * 採用ThreadLocal封裝Connection * 僅僅要線程是活動的,沒有結束,ThreadLocal是可訪問的,就能夠訪問本線程的connection *  * @author liang * */public class ConnectionManager {//使用ThreadLocal儲存Connection變數private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();/** * 串連Connection * @return */public static Connection getConnection(){//ThreadLocal取得當前線程的connectionConnection conn = connectionHolder.get();//假設ThreadLocal沒有綁定對應的Connection。建立一個新的Connection,//並將其儲存到本地線程變數中。if(conn == null){try {JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();Class.forName(jdbcConfig.getDriverName());conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());//將當前線程的Connection設定到ThreadLocalconnectionHolder.set(conn);} catch (ClassNotFoundException e) {e.printStackTrace();throw new ApplicationException("系統錯誤,請聯絡系統管理員");} catch (SQLException e) {e.printStackTrace();throw new ApplicationException("系統錯誤。請聯絡系統管理員");}}return conn;}/** * 關閉Connection,清除集合中的Connection */public static void closeConnection(){//ThreadLocal取得當前線程的connectionConnection conn = connectionHolder.get();//當前線程的connection不為空白時。關閉connection.if(conn != null){try{conn.close();//connection關閉之後,要從ThreadLocal的集合中清除ConnectionconnectionHolder.remove();}catch(SQLException e){e.printStackTrace();}}}}


      以下的代碼給大家示範了:ThreadLocal怎樣在同一個線程中能夠共用Connection資源。


package com.bjpowernode.drp.flowcard.manager.impl;import java.sql.Connection;import java.util.Date;import com.bjpowernode.drp.flowcard.dao.FlowCardDao;import com.bjpowernode.drp.flowcard.domain.FlowCard;import com.bjpowernode.drp.flowcard.manager.FlowCardManager;import com.bjpowernode.drp.util.ApplicationException;import com.bjpowernode.drp.util.BeanFactory;import com.bjpowernode.drp.util.ConnectionManager;import com.bjpowernode.drp.util.DaoException;import com.bjpowernode.drp.util.PageModel;public class FlowCardManagerImpl implements FlowCardManager {private FlowCardDao flowCardDao;//建構函式public FlowCardManagerImpl(){this.flowCardDao = (FlowCardDao) BeanFactory.getInstance().getDaoObject(FlowCardDao.class);}@Overridepublic void addFlowCard(FlowCard flowCard) throws ApplicationException {Connection conn = null;try{//從ThreadLocal中擷取線程相應的Connectionconn = ConnectionManager.getConnection();//開始事務ConnectionManager.beginTransaction(conn);//產生流向單單號String flowCardVouNo = flowCardDao.generateVouNo();//加入流向單主資訊flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);//加入流向單明細資訊flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());//提交事務ConnectionManager.commitTransaction(conn);}catch(DaoException e){//復原事務ConnectionManager.rollbackTransaction(conn);throw new ApplicationException("加入流向單失敗!

");}finally{//關閉Connection並從ThreadLocal集合中清除ConnectionManager.closeConnection();}}}


解析:

 

1、該類提供了線程局部變數。它獨立於變數的初始化副本

 

       大家可能對局部變數不太理解,為什麼不是成員變數或全域變數,此時就涉及到變數的範圍問題。

ThreadLocal具有比局部變數更大一點的範圍,在此範圍內資源能夠共用,線程是安全的。

       我們還瞭解到ThreadLocal並不是本地線程,而是一個線程變數,它僅僅是用來維護本地變數。

針對每一個線程提供自己的變數版本號碼,避免了多線程的衝突問題,每一個線程僅僅須要維護自己的版本號碼就好,彼此獨立,不會影響到對方。

 

2、每一個線程有自己的一個ThreadLocal。改動它並不影響其它線程

  

      我們依據以下這張圖能夠看到,向ThreadLocal裡面存東西就是建立了一個Map,一個線程相應一個Map集合,然後ThreadLocal把這個Map掛到當前的線程底下。一個key值相應一個value,這樣Map就僅僅屬於當前線程。(假設您不理解Map的特點能夠猛戳)




3、線上程消失之後。其線程局部執行個體的全部副本都會被記憶體回收(除非存在對這些副本的其它引用)。

 

      上面我們知道了變數副本的存放在了map中。當我們不在調用set,此時不在將引用指向該‘map’。而本線程退出時會運行資源回收操作。將申請的資源進行回收。事實上就是將引用設定為null。

這時已經不在有不論什麼引用指向該map,故而會被記憶體回收。


3、對照ThreadLocal和synchronized同步機制


同樣點:

        1、ThreadLocal和線程同步機制都能解決多線程中同樣變數的訪問衝突問題。

不同點:

       1、適用的情況不同

 

        在同步機制中,使用同步保證同一時間僅僅有一個線程訪問,不能同一時候訪問共用資源,否則就是出現錯誤。ThreadLocal則隔離了相關的資源,並在同一個線程中能夠共用這個資源。

彼此獨立,改動不會影響到對方。

 

       2、終於實現的效果不同

    

       對於多線程資源共用問題。同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式。前者僅提供一份變數。讓不同的線程排隊訪問。而後者為每個線程都提供了一份變數。因此能夠同一時候訪問而互不影響。

 

      上面部落格的連結相同也是線程同步機制synchronized的執行個體。大家能夠通過兩個執行個體體會一下它們的異同點,再加上異同點解析。相信您對它們已經有了非常深刻的認識。


4、一句話總結ThreadLocal


       ThreadLocal是解決安全執行緒問題一個非常好的思路。在非常多情況下。ThreadLocal比直接使用synchronized同步機制解決安全執行緒問題更簡單,更方便。而且程式擁有更高的並發性。




【java項目實戰】ThreadLocal封裝Connection,實現同一線程共用資源

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.