<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【java項(xiàng)目實(shí)戰(zhàn)】ThreadLocal封裝Connection,實(shí)現(xiàn)同一線程共享資源

          共 4478字,需瀏覽 9分鐘

           ·

          2022-04-01 20:59

          2058c1baeb76b1f33b9a9d7e9bff820a.webp

          ?線程安全一直是程序猿們關(guān)注的焦點(diǎn),多線程也一直是比較讓人頭疼的話題,想必大家曾經(jīng)也遇到過(guò)各種各種的問(wèn)題,我就不再累述了。當(dāng)然,解決方式也有很多,這篇給大家提供一種很好的解決線程安全問(wèn)題的思路。


          ?


          ? ? ? 首先,我們先簡(jiǎn)單的認(rèn)識(shí)一下ThreadLocal,之后是實(shí)例+解析,最后一句話總結(jié)。



          1、認(rèn)識(shí)一下ThreaLocal


          ? ? ? ?認(rèn)識(shí)ThreadLocal必須要通過(guò)api文檔,不僅僅具有說(shuō)服力,而且它會(huì)給你更加全面的解釋。下面我我給大家從api文檔上截取一張圖,并標(biāo)出來(lái)了七點(diǎn)需要重點(diǎn)理解的內(nèi)容,實(shí)例過(guò)后的解析也是重點(diǎn)解釋這七部分。

          c692ca7573d2d4a8bd963f25bef431af.webp




          ? ? ? 對(duì)于上面的內(nèi)容,不理解沒(méi)有關(guān)系,我們通過(guò)下面的實(shí)例加深一下理解,實(shí)例之后我會(huì)給大家一個(gè)更加深入的解釋。



          2、ThreaLocal封裝Connection實(shí)例+解析


          ? ? ? ?下面的代碼只是ThreaLocal封裝Connection的核心代碼,對(duì)于多余的內(nèi)容成功避開(kāi)就好,并且有一部分代碼是“dom4j解析xml文件,連接數(shù)據(jù)庫(kù)”的內(nèi)容,非常適合初學(xué)者,如有需要,請(qǐng)您移駕到此。



          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

          ?* 只要線程是活動(dòng)的,沒(méi)有結(jié)束,ThreadLocal是可訪問(wèn)的,就可以訪問(wèn)本線程的connection

          ?*?

          ?* @author liang

          ?*

          ?*/

          public class ConnectionManager {

          ?

          //使用ThreadLocal保存Connection變量

          private static ThreadLocal connectionHolder = new ThreadLocal();

          /**

          * 連接Connection

          * @return

          */

          public static Connection getConnection(){

          //ThreadLocal取得當(dāng)前線程的connection

          Connection conn = connectionHolder.get();

          //如果ThreadLocal沒(méi)有綁定相應(yīng)的Connection,創(chuàng)建一個(gè)新的Connection,

          //并將其保存到本地線程變量中。

          if(conn == null){

          try {

          JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();

          Class.forName(jdbcConfig.getDriverName());

          conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());

          //將當(dāng)前線程的Connection設(shè)置到ThreadLocal

          connectionHolder.set(conn);

          } catch (ClassNotFoundException e) {

          e.printStackTrace();

          throw new ApplicationException("系統(tǒng)錯(cuò)誤,請(qǐng)聯(lián)系系統(tǒng)管理員");

          } catch (SQLException e) {

          e.printStackTrace();

          throw new ApplicationException("系統(tǒng)錯(cuò)誤,請(qǐng)聯(lián)系系統(tǒng)管理員");

          }

          }

          return conn;

          }

          /**

          * 關(guān)閉Connection,清除集合中的Connection

          */

          public static void closeConnection(){

          //ThreadLocal取得當(dāng)前線程的connection

          Connection conn = connectionHolder.get();

          //當(dāng)前線程的connection不為空時(shí),關(guān)閉connection.

          if(conn != null){

          try{

          conn.close();

          //connection關(guān)閉之后,要從ThreadLocal的集合中清除Connection

          connectionHolder.remove();

          }catch(SQLException e){

          e.printStackTrace();

          }

          ?

          }

          }


          ? ? ? 下面的代碼給大家演示了:ThreadLocal如何在同一個(gè)線程中可以共享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;

          //構(gòu)造函數(shù)

          public FlowCardManagerImpl(){

          this.flowCardDao = (FlowCardDao) BeanFactory.getInstance().getDaoObject(FlowCardDao.class);

          }

          @Override

          public void addFlowCard(FlowCard flowCard) throws ApplicationException {

          Connection conn = null;

          try{

          //從ThreadLocal中獲取線程對(duì)應(yīng)的Connection

          conn = ConnectionManager.getConnection();

          //開(kāi)始事務(wù)

          ConnectionManager.beginTransaction(conn);

          //生成流向單單號(hào)

          String flowCardVouNo = flowCardDao.generateVouNo();

          //添加流向單主信息

          flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);

          //添加流向單明細(xì)信息

          flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());

          //提交事務(wù)

          ConnectionManager.commitTransaction(conn);

          }catch(DaoException e){

          //回滾事務(wù)

          ConnectionManager.rollbackTransaction(conn);

          throw new ApplicationException("添加流向單失??!");

          }finally{

          //關(guān)閉Connection并從ThreadLocal集合中清除

          ConnectionManager.closeConnection();

          }

          }

          }


          解析:


          ?


          1、該類提供了線程局部變量,它獨(dú)立于變量的初始化副本


          ?


          ? ? ? ?大家可能對(duì)局部變量不太理解,為什么不是成員變量或全局變量,此時(shí)就涉及到變量的作用域問(wèn)題。ThreadLocal具有比局部變量更大一點(diǎn)的作用域,在此作用域內(nèi)資源可以共享,線程是安全的。


          ? ? ? ?我們還了解到ThreadLocal并不是本地線程,而是一個(gè)線程變量,它只是用來(lái)維護(hù)本地變量。針對(duì)每個(gè)線程提供自己的變量版本,避免了多線程的沖突問(wèn)題,每個(gè)線程只需要維護(hù)自己的版本就好,彼此獨(dú)立,不會(huì)影響到對(duì)方。


          ?


          2、每個(gè)線程有自己的一個(gè)ThreadLocal,修改它并不影響其他線程


          ??


          ? ? ? 我們根據(jù)下面這張圖可以看到,向ThreadLocal里面存東西就是創(chuàng)建了一個(gè)Map,一個(gè)線程對(duì)應(yīng)一個(gè)Map集合,然后ThreadLocal把這個(gè)Map掛到當(dāng)前的線程底下,一個(gè)key值對(duì)應(yīng)一個(gè)value,這樣Map就只屬于當(dāng)前線程。


          98fc08f2ce14b1390e828d48e8e8b811.webp



          3、在線程消失之后,其線程局部實(shí)例的所有副本都會(huì)被垃圾回收(除非存在對(duì)這些副本的其他引用)。

          ?


          ? ? ? 上面我們知道了變量副本的存放在了map中,當(dāng)我們不在調(diào)用set,此時(shí)不在將引用指向該‘map’,而本線程退出時(shí)會(huì)執(zhí)行資源回收操作,將申請(qǐng)的資源進(jìn)行回收,其實(shí)就是將引用設(shè)置為null。這時(shí)已經(jīng)不在有任何引用指向該map,故而會(huì)被垃圾回收。



          3、對(duì)比ThreadLocal和synchronized同步機(jī)制


          相同點(diǎn):

          ? ? ? ? 1、ThreadLocal和線程同步機(jī)制都能解決多線程中相同變量的訪問(wèn)沖突問(wèn)題。


          不同點(diǎn):

          ? ? ? ?1、適用的情況不同


          ?


          ? ? ? ? 在同步機(jī)制中,使用同步保證同一時(shí)間只有一個(gè)線程訪問(wèn),不能同時(shí)訪問(wèn)共享資源,否則就是出現(xiàn)錯(cuò)誤。ThreadLocal則隔離了相關(guān)的資源,并在同一個(gè)線程中可以共享這個(gè)資源。彼此獨(dú)立,修改不會(huì)影響到對(duì)方。


          ?


          ? ? ? ?2、最終實(shí)現(xiàn)的效果不同


          ? ??


          ? ? ? ?對(duì)于多線程資源共享問(wèn)題,同步機(jī)制采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問(wèn),而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問(wèn)而互不影響。

          ?




          4、一句話總結(jié)ThreadLocal


          ? ? ? ?ThreadLocal是解決線程安全問(wèn)題一個(gè)很好的思路,在很多情況下,ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問(wèn)題更簡(jiǎn)單,更方便,并且程序擁有更高的并發(fā)性。

          ————————————————


          9b42b0acf7f7feea0e173797bc729764.webp


          瀏覽 105
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天干在线影院 | 日本天天操 | 青青草精品在线视频 | 美女裸体av | 亚洲AV日韩AV高潮喷人人爽 |