ThreadLocalを使ってMybatisのSql Sessionオブジェクトを管理します.

11023 ワード

自動回転http://blog.csdn.net/qq_29227939/articale/detail/52029065
public class MybatisUtil {

	private static SqlSessionFactory factory;
	//         .
	private static ThreadLocal localSessions = new ThreadLocal();

	static {
		Reader reader = null;
		try {
			//   Mybatis     
			reader = Resources.getResourceAsReader("mybatis.xml");
			//   SqlSessionFactory  .
			factory = new SqlSessionFactoryBuilder().build(reader);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	//   Session  
	public static SqlSession getSession() {
		SqlSession session = localSessions.get();
		if (session == null) {
			session = factory.openSession();
			localSessions.set(session);
		}
		return session;
	}

	//   session   
	public static void closeSession() {
		SqlSession session = localSessions.get();
		if (session != null) {
			session.close();
			localSessions.remove();
		}
	}
}
      まず、ThreadLocalは共有対象のマルチスレッドアクセス問題を解決するためのものではなく、通常、ThreadLocal.setを介してスレッドに送る対象はこのスレッド自身が使用する対象であり、他のスレッドはアクセスする必要がなく、アクセスできない.各スレッドにアクセスするのは、異なるオブジェクトです.         また、ThreadLocalは、各スレッドがそれぞれ独立したオブジェクトを保持できるようにしており、ThreadLocal.set()によって実現されるのではなく、各スレッドのnewオブジェクトの操作によって作成されたオブジェクトであり、スレッドごとに一つが作成されており、どのオブジェクトのコピーやコピーではない.ThreadLocal.set()によってこの新たに作成されたオブジェクトの引用を各スレッドの自分の1つのmapに保存します.各スレッドにはこのようなmapがあります.ThreadLocal.get()を実行すると、各スレッドが自分のmapからオブジェクトを取り出すので、取り出したのはそれぞれのスレッドの中のオブジェクトです.ThreadLocalの例はmapのkeyとして使用されます.         ThreadLocal.setに入るものが元々複数のスレッドで共有されている同一のオブジェクトである場合、複数のスレッドのThreadLocal.get()が取得したものはやはりこの共有対象自体であり、同時にアクセスする問題がある. 次に、ヒベルナの典型的なThreadLocalの応用を見てみましょう.
     private static final ThreadLocal threadSession = new ThreadLocal();  
      
    public static Session getSession() throws InfrastructureException {  
        Session s = (Session) threadSession.get();  
        try {  
            if (s == null) {  
                s = getSessionFactory().openSession();  
                threadSession.set(s);  
            }  
        } catch (HibernateException ex) {  
            throw new InfrastructureException(ex);  
        }  
        return s;  
    }  
        get Session()方法では、まず現在スレッドにsessionが入っているかどうかを判断します.まだない場合は、session Factory().openSession()によりsessionを作成し、sessiotをスレッドにセットして、実際に現在スレッドのThreadLocal Mapにセットします.このセッションに対する唯一の引用は現在のスレッドの中のThreadLocal Mapであり、threadSessionはこの値のkeyとして、このセッションを取得するにはthreadSession.get()を通じて得られます.中で実行される操作は実際に当スレッドの中のThreadLocal Mapを先に取得して、threadSessionをkeyの対応値として取り出します.このsessionは、スレッドのプライベート変数に相当し、publicのものではない. 
        明らかに、他のスレッドではこのセッションは取れません.彼らも自分のThreadLocal Mapの中のものしか取れません.sessionが複数のスレッドを共有して使うなら、まだ乱れていません. 
        もしThreadLocalを使わなかったらどうやって実現しますか?actionでsessionを作成して、serviceとdaoにsessionを一つずつ送るのは面倒くさいかもしれません.あるいは、自分で静的なmapを定義して、現在のthreadをkeyとして、作成されたsessionを値として、putからmapにしてもいいはずです.これも一般的な考え方ですが、実は、ThreadLocalの実装は、スレッドごとにmapがあり、ThreadLocalのインスタンスをkeyとしています.また、スレッドが破壊された時にはそれに応じたものも一緒に廃棄されました.これら以外に何か他の利点がありますか?
        つまり、ThreadLocalはオブジェクト共有アクセス問題を解決するためのものではなく、主にオブジェクトを保持する方法とパラメータ伝達を回避するための便利なオブジェクトアクセス方式を提供している.2点を要約しました 1です.各スレッドの中には自分のThreadLocal Map類のオブジェクトがあります.スレッド自体のオブジェクトをその中に保持します.各スレッドはそれぞれ、スレッドは自分のオブジェクトに正しくアクセスできます. 
2です.共有されているThreadLocalの静的な例をkeyとして、異なるオブジェクトの参照を異なるスレッドのThreadLocal Mapに保存し、スレッド実行の各所でこの静的なThreadLocalのインスタンスのget()方法によって、自分のスレッドに保存されているそのオブジェクトを取得して、パラメータとして転送することの面倒を回避する.
        もちろん、本来のスレッド共有の対象を、ThreadLocal.set()をスレッドに置いても良いので、パラメータ伝達を回避するアクセス方式が可能ですが、get()が同じ共有オブジェクトに到達していることに注意し、同時にアクセスする問題は他の手段によって解決されます.しかし、一般的にスレッド共有の対象は、クラスの静的変数として設定することにより、簡単にアクセスできます.         ThreadLocalのアプリケーションの場合、スレッドの多例(スレッドごとに一例に対応)によるオブジェクトのアクセスが最適だと思います.このオブジェクトは多くのところで使われています.次に、ThreadLocalの実現原理(jdk 1.5ソース)を見てみます.
     public class ThreadLocal {  
        /** 
         * ThreadLocals rely on per-thread hash maps attached to each thread 
         * (Thread.threadLocals and inheritableThreadLocals).  The ThreadLocal 
         * objects act as keys, searched via threadLocalHashCode.  This is a 
         * custom hash code (useful only within ThreadLocalMaps) that eliminates 
         * collisions in the common case where consecutively constructed 
         * ThreadLocals are used by the same threads, while remaining well-behaved 
         * in less common cases. 
         */  
        private final int threadLocalHashCode = nextHashCode();  
      
        /** 
         * The next hash code to be given out. Accessed only by like-named method. 
         */  
        private static int nextHashCode = 0;  
      
        /** 
         * The difference between successively generated hash codes - turns 
         * implicit sequential thread-local IDs into near-optimally spread 
         * multiplicative hash values for power-of-two-sized tables. 
         */  
        private static final int HASH_INCREMENT = 0x61c88647;  
      
        /** 
         * Compute the next hash code. The static synchronization used here 
         * should not be a performance bottleneck. When ThreadLocals are 
         * generated in different threads at a fast enough rate to regularly 
         * contend on this lock, memory contention is by far a more serious 
         * problem than lock contention. 
         */  
        private static synchronized int nextHashCode() {  
            int h = nextHashCode;  
            nextHashCode = h + HASH_INCREMENT;  
            return h;  
        }  
      
        /** 
         * Creates a thread local variable. 
         */  
        public ThreadLocal() {  
        }  
      
        /** 
         * Returns the value in the current thread's copy of this thread-local 
         * variable.  Creates and initializes the copy if this is the first time 
         * the thread has called this method. 
         * 
         * @return the current thread's value of this thread-local 
         */  
        public T get() {  
            Thread t = Thread.currentThread();  
            ThreadLocalMap map = getMap(t);  
            if (map != null)  
                return (T)map.get(this);  
      
            // Maps are constructed lazily.  if the map for this thread  
            // doesn't exist, create it, with this ThreadLocal and its  
            // initial value as its only entry.  
            T value = initialValue();  
            createMap(t, value);  
            return value;  
        }  
      
        /** 
         * Sets the current thread's copy of this thread-local variable 
         * to the specified value.  Many applications will have no need for 
         * this functionality, relying solely on the {@link #initialValue} 
         * method to set the values of thread-locals. 
         * 
         * @param value the value to be stored in the current threads' copy of 
         *        this thread-local. 
         */  
        public void set(T value) {  
            Thread t = Thread.currentThread();  
            ThreadLocalMap map = getMap(t);  
            if (map != null)  
                map.set(this, value);  
            else  
                createMap(t, value);  
        }  
      
        /** 
         * Get the map associated with a ThreadLocal. Overridden in 
         * InheritableThreadLocal. 
         * 
         * @param  t the current thread 
         * @return the map 
         */  
        ThreadLocalMap getMap(Thread t) {  
            return t.threadLocals;  
        }  
      
        /** 
         * Create the map associated with a ThreadLocal. Overridden in 
         * InheritableThreadLocal. 
         * 
         * @param t the current thread 
         * @param firstValue value for the initial entry of the map 
         * @param map the map to store. 
         */  
        void createMap(Thread t, T firstValue) {  
            t.threadLocals = new ThreadLocalMap(this, firstValue);  
        }  
      
        .......  
      
        /** 
         * ThreadLocalMap is a customized hash map suitable only for 
         * maintaining thread local values. No operations are exported 
         * outside of the ThreadLocal class. The class is package private to 
         * allow declaration of fields in class Thread.  To help deal with 
         * very large and long-lived usages, the hash table entries use 
         * WeakReferences for keys. However, since reference queues are not 
         * used, stale entries are guaranteed to be removed only when 
         * the table starts running out of space. 
         */  
        static class ThreadLocalMap {  
      
        ........  
      
        }  
      
    }  
には、ThreadLocalクラスの変数はこの3つのint型しか見られません.
     private final int threadLocalHashCode = nextHashCode();  
    private static int nextHashCode = 0;  
    private static final int HASH_INCREMENT = 0x61c88647;  
        ThreadLocalの例としての変数は、threadLocal HashCodeの一つであり、next HashCodeとHASH_のみである.INCREMENTはThreadLocal類の静的変数ですが、実はHASH_INCREMENTは、連続して割り当てられた2つのThreadLocalの例のthreadLocal HashCodeの値の増分を表し、next HashCodeは、すぐに割り当てられる次のThreadLocalのインスタンスのthreadLocal HashCodeの値を表している. 
        ちょっと見てください.ThreadLocalの一例であるnew ThreadLocalを作成する時にどのような操作をしましたか?上から構造関数ThreadLocalを見ましたが、何の操作もありません.唯一の操作はこの文です.
private final int threadLocalHashCode = nextHashCode(); 
next HashCodeは何をしましたか?
     private static synchronized int nextHashCode() {  
        int h = nextHashCode;  
        nextHashCode = h + HASH_INCREMENT;  
        return h;  
    }  
        つまり、ThreadLocal類の次のhashCodeの値であるnext HashCodeの値をインスタンスのthreadLocal HashCodeに付与し、next HashCodeの値をHASH_に増加させるということです.INCREMENTという値です. 
        したがって、ThreadLocalの例の変数は、このthreadLocal HashCodeだけであり、かつfinalであり、異なるThreadLocalの例を区別するために使用されます.ThreadLocal類は主にツールとして使用されますが、ThreadLocal.setに入る対象はどこにありますか? 
上のセットの方法を見てください.二つを合わせて一つになります.
ThreadLocalMap map = Thread.currentThread().threadLocals;  
このThreadLocal Map類はThreadLocalで定義されている内部クラスですが、その例はThreadクラスで使われています.
     public class Thread implements Runnable {  
        ......  
      
        /* ThreadLocal values pertaining to this thread. This map is maintained 
         * by the ThreadLocal class. */  
        ThreadLocal.ThreadLocalMap threadLocals = null;    
        ......  
    }  
これを見てください
     if (map != null)  
        map.set(this, value);  
        つまり、このThreadLocalの例をkeyとし、保持する対象を値として、現在のスレッドのThreadLocal Mapに設定し、get()メソッドもコードを見て分かります.VIA:http://www.iteye.com/topic/103804
使用ThreadLocal管理Mybatis中SqlSession对象_第1张图片