久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

研究java.lang.ThreadLocal類

 燮羽 2010-10-26

一,、概述
ThreadLocal是什么呢,?其實ThreadLocal并非是一個線程的本地實現(xiàn)版本,它并不是一個Thread,,而是threadlocalvariable(線程局部變量),。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單,,就是為每一個使用該變量的線程都提供一個變量值的副本,,是Java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,,而不會和其它線程的副本沖突,。
從線程的角度看,每個線程都保持一個對其線程局部變量副本的隱式引用,,只要線程是活動的并且 ThreadLocal 實例是可訪問的,;在線程消失之后,其線程局部實例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用),。
通過ThreadLocal存取的數(shù)據(jù),,總是與當(dāng)前線程相關(guān),也就是說,,JVM 為每個運行的線程,,綁定了私有的本地實例存取空間,,從而為多線程環(huán)境常出現(xiàn)的并發(fā)訪問問題提供了一種隔離機制。
ThreadLocal是如何做到為每一個線程維護變量的副本的呢,?其實實現(xiàn)的思路很簡單,,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本,。
概括起來說,,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,,而ThreadLocal采用了“以空間換時間”的方式,。前者僅提供一份變量,讓不同的線程排隊訪問,,而后者為每一個線程都提供了一份變量,,因此可以同時訪問而互不影響。
二,、API說明
ThreadLocal()
          創(chuàng)建一個線程本地變量,。
T get()
          返回此線程局部變量的當(dāng)前線程副本中的值,如果這是線程第一次調(diào)用該方法,,則創(chuàng)建并初始化此副本,。
protected T initialValue()
          返回此線程局部變量的當(dāng)前線程的初始值。最多在每次訪問線程來獲得每個線程局部變量時調(diào)用此方法一次,,即線程第一次使用 get() 方法訪問變量的時候,。如果線程先于 get 方法調(diào)用 set(T) 方法,則不會在線程中再調(diào)用 initialValue 方法,。
   若該實現(xiàn)只返回 null,;如果程序員希望將線程局部變量初始化為 null 以外的某個值,則必須為 ThreadLocal 創(chuàng)建子類,,并重寫此方法,。通常,將使用匿名內(nèi)部類,。initialValue 的典型實現(xiàn)將調(diào)用一個適當(dāng)?shù)臉?gòu)造方法,,并返回新構(gòu)造的對象。
void remove()
          移除此線程局部變量的值,。這可能有助于減少線程局部變量的存儲需求,。如果再次訪問此線程局部變量,那么在默認情況下它將擁有其 initialValue,。
void set(T value)
          將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為指定值,。許多應(yīng)用程序不需要這項功能,它們只依賴于 initialValue() 方法來設(shè)置線程局部變量的值。
在程序中一般都重寫initialValue方法,,以給定一個特定的初始值,。
三、典型實例
1,、Hiberante的Session 工具類HibernateUtil
這個類是Hibernate官方文檔中HibernateUtil類,,用于session管理。
public class HibernateUtil {
    private static Log log = LogFactory.getLog(HibernateUtil.class);
    private static final SessionFactory sessionFactory;     //定義SessionFactory
    static {
        try {
            // 通過默認配置文件hibernate.cfg.xml創(chuàng)建SessionFactory
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            log.error("初始化SessionFactory失??!", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    //創(chuàng)建線程局部變量session,用來保存Hibernate的Session
    public static final ThreadLocal session = new ThreadLocal();
    /**
     * 獲取當(dāng)前線程中的Session
     * @return Session
     * @throws HibernateException
     */
    public static Session currentSession() throws HibernateException {
        Session s = (Session) session.get();
        // 如果Session還沒有打開,,則新開一個Session
        if (s == null) {
            s = sessionFactory.openSession();
            session.set(s);         //將新開的Session保存到線程局部變量中
        }
        return s;
    }
    public static void closeSession() throws HibernateException {
        //獲取線程局部變量,,并強制轉(zhuǎn)換為Session類型
        Session s = (Session) session.get();
        session.set(null);
        if (s != null)
            s.close();
    }
}
在這個類中,由于沒有重寫ThreadLocal的initialValue()方法,,則首次創(chuàng)建線程局部變量session其初始值為null,第一次調(diào)用currentSession()的時候,,線程局部變量的get()方法也為null,。因此,對session做了判斷,,如果為null,,則新開一個Session,并保存到線程局部變量session中,,這一步非常的關(guān)鍵,,這也是“public static final ThreadLocal session = new ThreadLocal()”所創(chuàng)建對象session能強制轉(zhuǎn)換為Hibernate Session對象的原因。
2,、另外一個實例
創(chuàng)建一個Bean,,通過不同的線程對象設(shè)置Bean屬性,保證各個線程Bean對象的獨立性,。
/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-11-23
* Time: 10:45:02
* 學(xué)生
*/
public class Student {
    private int age = 0;   //年齡
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
/**
* Created by IntelliJ IDEA.
* User: leizhimin
* Date: 2007-11-23
* Time: 10:53:33
* 多線程下測試程序
*/
public class ThreadLocalDemo implements Runnable {
    //創(chuàng)建線程局部變量studentLocal,,在后面你會發(fā)現(xiàn)用來保存Student對象
    private final static ThreadLocal studentLocal = new ThreadLocal();
    public static void main(String[] agrs) {
        ThreadLocalDemo td = new ThreadLocalDemo();
        Thread t1 = new Thread(td, "a");
        Thread t2 = new Thread(td, "b");
        t1.start();
        t2.start();
    }
    public void run() {
        accessStudent();
    }
    /**
     * 示例業(yè)務(wù)方法,用來測試
     */
    public void accessStudent() {
        //獲取當(dāng)前線程的名字
        String currentThreadName = Thread.currentThread().getName();
        System.out.println(currentThreadName + " is running!");
        //產(chǎn)生一個隨機數(shù)并打印
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println("thread " + currentThreadName + " set age to:" + age);
        //獲取一個Student對象,,并將隨機數(shù)年齡插入到對象屬性中
        Student student = getStudent();
        student.setAge(age);
        System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());
    }
    protected Student getStudent() {
        //獲取本地線程變量并強制轉(zhuǎn)換為Student類型
        Student student = (Student) studentLocal.get();
        //線程首次執(zhí)行此方法的時候,,studentLocal.get()肯定為null
        if (student == null) {
            //創(chuàng)建一個Student對象,并保存到本地線程變量studentLocal中
            student = new Student();
            studentLocal.set(student);
        }
        return student;
    }
}
運行結(jié)果:
a is running! 
thread a set age to:76 
b is running! 
thread b set age to:27 
thread a first read age is:76 
thread b first read age is:27 
thread a second read age is:76 
thread b second read age is:27
可以看到a,、b兩個線程age在不同時刻打印的值是完全相同的,。這個程序通過妙用ThreadLocal,既實現(xiàn)多線程并發(fā),,游兼顧數(shù)據(jù)的安全性,。
四、總結(jié)
ThreadLocal使用場合主要解決多線程中數(shù)據(jù)數(shù)據(jù)因并發(fā)產(chǎn)生不一致問題,。ThreadLocal為每個線程的中并發(fā)訪問的數(shù)據(jù)提供一個副本,,通過訪問副本來運行業(yè)務(wù),,這樣的結(jié)果是耗費了內(nèi)存,單大大減少了線程同步所帶來性能消耗,,也減少了線程并發(fā)控制的復(fù)雜度,。
ThreadLocal不能使用原子類型,只能使用Object類型,。ThreadLocal的使用比synchronized要簡單得多,。
ThreadLocal和Synchonized都用于解決多線程并發(fā)訪問。但是ThreadLocal與synchronized有本質(zhì)的區(qū)別,。synchronized是利用鎖的機制,,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本,,使得每個線程在某一時間訪問到的并不是同一個對象,,這樣就隔離了多個線程對數(shù)據(jù)的數(shù)據(jù)共享。而Synchronized卻正好相反,,它用于在多個線程間通信時能夠獲得數(shù)據(jù)共享,。
Synchronized用于線程間的數(shù)據(jù)共享,而ThreadLocal則用于線程間的數(shù)據(jù)隔離,。
當(dāng)然ThreadLocal并不能替代synchronized,它們處理不同的問題域,。Synchronized用于實現(xiàn)同步機制,比ThreadLocal更加復(fù)雜,。
五,、ThreadLocal使用的一般步驟
1、在多線程的類(如ThreadDemo類)中,,創(chuàng)建一個ThreadLocal對象threadXxx,,用來保存線程間需要隔離處理的對象xxx。
2,、在ThreadDemo類中,,創(chuàng)建一個獲取要隔離訪問的數(shù)據(jù)的方法getXxx(),在方法中判斷,,若ThreadLocal對象為null時候,,應(yīng)該new()一個隔離訪問類型的對象,并強制轉(zhuǎn)換為要應(yīng)用的類型,。
3,、在ThreadDemo類的run()方法中,通過getXxx()方法獲取要操作的數(shù)據(jù),,這樣可以保證每個線程對應(yīng)一個數(shù)據(jù)對象,,在任何時刻都操作的是這個對象。
 

通常在多線程中,當(dāng)使用ThreadLocal維護變量時,,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本

      實現(xiàn)線程本地類其實不難:以當(dāng)前線程為key,要保存的對象為value

      public class ThreadLocalSample {

           private Map map = Collections.synchronizedMap(new HashMap());

          

           public void set(Object value) {

               map.put(Thread.currentThread(), value);

           }

           public Object get() {

               Object value = map.get(Thread.currentThread());

               return value;

           }

      }

      ThreadLocal可用在Servlet的過濾器中,,比如:每一個請求都由一個Connection來操作數(shù)據(jù)庫,,由于Servlet只有一個實例,所以應(yīng)該是每個線程用一個連接,,而不是所有線程用一個Connection,,因此需要用到ThreadLocal類;由于Servlet是在Filter鏈的調(diào)用中點執(zhí)行,,即Filter1->Filter2->...->Servlet->Filter2->Filter1,,因此:可以用一個Filter,在這個Filter調(diào)用下一個Filter前初始化連接,,并將其放入ThreadLocal中,,在調(diào)用又回到這個Filter時,得到連接并關(guān)閉,。

      代碼如下:

      public class TransactionManageFilter implements Filter {

              private FilterConfig config;

              public void init(FilterConfig config) throws ServletException {
                  this.config = config;

              }

              public void destroy() {
                 config = null;
              }

              
               public void doFilter(ServletRequest request, ServletResponse response,
                                              FilterChain chain) throws IOException, ServletException {

                      Connection conn = ConnectionManager.currentConnection();

                      try {

                            conn.setAutoCommit(false);

                            chain.doFilter(request, response, chain);

                            conn.commit();

                      } catch (Exception e) {

                            conn.rollback();

                      } finally {

                            try {

                               conn.setAutoCommit(true);

                               conn.close();

                               ConnectionManager.removeConnection();

                            } catch (Exception e) {}

                      }

               }

      }

      public class ConnectionManager {

          private static ThreadLocal currConn = new ThreadLocal();

      

          public static Connection currentConnection() {

              Object obj = currConn.get();

              if (obj != null) {

                 return (Connection)obj;

              } else {

                  Connection conn = ConnectionFactory.getConnection();

                  currConn.set(conn);

                  return conn;

              }

          }

         public static void removeConnection() {

             Object obj = currConn.get();

             if (obj != null) {

                currConn.set(null);

             }

        }

     }

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多