マルチスレッドの学習の概要(4)

ThreadLocalの及InheritableThreadLocal

1. ThreadLocalのは何ですか?

簡単に言えば、その後、JDK ThreadLocal変数のメンテナンスを使用して、独立変数のコピーを提供するために、スレッドごとにThreadLocal変数を使用するので、各スレッドは独立して、他の影響を与えることなく、そのコピーを変更することができますスレッドは、コピーし、対応します。

コードは示しています。

package com.my.thread;
   public class ThreadDemo2 {
       private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
           @Override
           public Integer initialValue() {
               return 0;
           }
       };
       static class ThreadDemo implements Runnable {
           @Override
           public void run() {
               for (int i = 0; i < 1000; i++) {
                   threadLocal.set(threadLocal.get() + 1);
               }
               System.out.println("thread :" + Thread.currentThread().getId() + " is" + threadLocal.get());
           }
       }
       public static void main(String[] args) {
           for (int i = 0; i < 10; i++) {
               new Thread(new ThreadDemo()).start();
           }
       }
   }
结果:
    thread :11 is1000
    thread :12 is1000
    thread :13 is1000
    thread :14 is1000
    thread :17 is1000
    thread :16 is1000
    thread :15 is1000
    thread :18 is1000
    thread :19 is1000
    thread :20 is1000

上記の結果から分かるように、すべての操作の出力は、スレッド間で影響を受けません。まったく共有性が混乱1000 OP命令を生じないからです。

(コードの)ThreadLocalの原則分析

ThreadLocal.ThreadLocalMap threadLocals = null;
        protected T initialValue() {
            return null;
        }
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
        private T setInitialValue() {
            T value = initialValue();
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
            return value;
        }
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
        ThreadLocalMap getMap(Thread t) {
           return t.threadLocals;
        }

概要

我々はThreadLocalのを使用当初から、あなたが初期値に割り当てられているはinitialValue()メソッドをオーバーライドすることができます。
1.方法が第1の設定値(T値)を設定するために呼び出す必要がある場合は、最初に現在のスレッドを得ることがGetMapリクエスト(t)を使用します。 ThreadLocalMapオブジェクトのコレクション。
判断がcreateMapによって作成され、割り当てられます場合は(スレッドT、T firstValue)がnullです。
nullでない場合は、説明がThreadLocalMapコレクションされている、あなたが直接コレクションに追加することができます。
2.最初の呼び出しは、取得した場合()メソッドは、ThreadLocalMap現在のスレッドオブジェクトのコレクションを取得しますGetMapリクエスト(t)を移動します。
そうでない場合ThreadLocalMapコレクションがnullであるから、それを得る。
ヌルは、それがsetInitialValue()メソッド、およびcreateMapによって(スレッドtを実行する場合は、T firstValue)が作成され、割り当てられました。

場合はここで、彼らはそれを理解する必要があります。私たちは定義オブジェクトのThreadLocalすると、ThreadLocalMapスレッドのコレクションを作成しません。しかし、呼び出しが取得()と判断するために作成した設定方法、。
したがって、各スレッドがありますThreadLocalMapは、自分用のスレッドの独自のセットを持っています。

そして、スレッドの終了は、それをどのように扱うかであるとき?

private void exit() {
            if (group != null) {
                group.threadTerminated(this);
                group = null;
            }
            target = null;
            threadLocals = null;
            inheritableThreadLocals = null;
            inheritedAccessControlContext = null;
            blocker = null;
            uncaughtExceptionHandler = null;
        }

糸の端部は出口を呼び出す場合()メソッドはthreadLocals =ヌル;.そしてThreadLocalMapコレクションはGCを破壊をクリーンアップしてくるのを待って、null参照あろう。行って、上記から分かるように
、このような治療は全く問題なかったが、スレッドと内部のプールは同じではありません。

    package com.my.thread;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class ThreadLocalTest {

    	//创建一个Integer本地线程变量
    	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
    		@Override
    		public Integer initialValue() {
    			return 0;
    		}
    	};
    	static class ThreadDemo implements Runnable {
    		@Override
    		public void run() {
    			for (int i = 0; i < 1000; i++) {
    				threadLocal.set(threadLocal.get() + 1);
    			}
    			System.out.println("thread :" + Thread.currentThread().getId() + " is" + threadLocal.get());
    			//threadLocal.remove();
    		}
    	}
    	public static void main(String[] args) {
    		ExecutorService executorService= Executors.newFixedThreadPool(5);
    		for (int i = 0; i < 10; i++) {
    			executorService.submit(new Thread(new ThreadDemo()));
    		}
    	}

    }

结果:
    thread :12 is1000
    thread :16 is1000
    thread :18 is1000
    thread :16 is2000
    thread :16 is3000
    thread :16 is4000
    thread :18 is2000
    thread :12 is2000
    thread :14 is1000
    thread :20 is1000

スレッドを蓄積しながら、実行スレッドプールのスレッドで、殺されないためです。、見られますが、次のタスクを待ってからスレッド倍に戻すことができます。
私たちは//threadLocal.removeとき();注意開封後、以下に示すように結果。

结果:
       thread :14 is1000
       thread :14 is1000
       thread :14 is1000
       thread :14 is1000
       thread :12 is1000
       thread :14 is1000
       thread :12 is1000
       thread :16 is1000
       thread :18 is1000
       thread :20 is1000

私たちは、結果はそうにThreadLocalを使用してスレッド・プールに、ThreadLocalのは限り値として、あなたが正常に使用することができ、使用後に空に1000で、見ることができます。

2.InheritableThreadLocal

なぜこのInheritableThreadLocalを使うのか?

まず、ThreadLocalのできる私たちがアクションを実行するために、スレッドBスレッドを起動する。のシーンのニーズについて話しましょう、しかし、我々は必要なスレッドAのこの時期に、スレッドBでのThreadLocalのスレッドの値の一部を使用する必要がありますBは、スレッドに送信されます。

コードは、シーンを示しています。

package com.my.thread;
public class ThreadLocalTest1 {
        private static  InheritableThreadLocal<Integer> inheritableThreadLocal = new  InheritableThreadLocal<Integer>();
        static class ThreadDemo implements Runnable {
        		@Override
        		public void run() {
        			for (int i = 0; i < 1000; i++) {
        				inheritableThreadLocal.set(inheritableThreadLocal.get() + 1);
        			}
        			System.out.println("thread :" + Thread.currentThread().getId() + " is" + inheritableThreadLocal.get());
        		}
        	}
        	public static void main(String[] args) {
        		inheritableThreadLocal.set(24);
        		for (int i = 0; i < 10; i++) {
        			new Thread(new ThreadDemo()).start();
        		}
        	}
        }
结果:
    thread :12 is1024
    thread :11 is1024
    thread :13 is1024
    thread :14 is1024
    thread :17 is1024
    thread :18 is1024
    thread :19 is1024
    thread :20 is1024
    thread :15 is1024
    thread :16 is1024

上から見ることができ、メインスレッドから24は、子スレッドに渡されます。最後の印刷1024

InheritableThreadLocal原則分析

InheritableThreadLocalソースコード:

    public class InheritableThreadLocal<T> extends ThreadLocal<T> {
        protected T childValue(T parentValue) {
            return parentValue;
        }

        ThreadLocalMap getMap(Thread t) {
            return t.inheritableThreadLocals;
        }

        void createMap(Thread t, T firstValue) {
            t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
        }
    }

コードのThreadクラスの一部:

    public class Thread implements Runnable {
        private void init(ThreadGroup g, Runnable target, String name,
                              long stackSize, AccessControlContext acc) {
                if (name == null) {
                    throw new NullPointerException("name cannot be null");
                }

                this.name = name.toCharArray();

                Thread parent = currentThread();
                SecurityManager security = System.getSecurityManager();
                if (g == null) {
                    /* Determine if it's an applet or not */

                    /* If there is a security manager, ask the security manager
                       what to do. */
                    if (security != null) {
                        g = security.getThreadGroup();
                    }

                    /* If the security doesn't have a strong opinion of the matter
                       use the parent thread group. */
                    if (g == null) {
                        g = parent.getThreadGroup();
                    }
                }

                /* checkAccess regardless of whether or not threadgroup is
                   explicitly passed in. */
                g.checkAccess();

                /*
                 * Do we have the required permissions?
                 */
                if (security != null) {
                    if (isCCLOverridden(getClass())) {
                        security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                    }
                }

                g.addUnstarted();

                this.group = g;
                this.daemon = parent.isDaemon();
                this.priority = parent.getPriority();
                if (security == null || isCCLOverridden(parent.getClass()))
                    this.contextClassLoader = parent.getContextClassLoader();
                else
                    this.contextClassLoader = parent.contextClassLoader;
                this.inheritedAccessControlContext =
                        acc != null ? acc : AccessController.getContext();
                this.target = target;
                setPriority(priority);
                if (parent.inheritableThreadLocals != null)
                    this.inheritableThreadLocals =
                        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
                /* Stash the specified stack size in case the VM cares */
                this.stackSize = stackSize;

                /* Set thread ID */
                tid = nextThreadID();
            }

    }

要約:

ここにあなたが見ることができる、InheritableThreadLocalは、実際にThreadLocalを継承し、GetMapリクエスト(スレッドt)とcreateMap(糸T、T firstValue)と3つのメソッドchildValue(T parentValue)を書き換えます。値は、マップ・セットに割り当てられている変数inheritableThreadLocalsスレッドです。
そして、我々は、スレッドのソースコードを見たとき、私たちはINITの1()メソッドを見つけることができます:
スレッドの親= currentThreadを();
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
ここを参照してください、私はあなたが理解して信じていますそれが起こるのか。

単に私たちがInheritableThreadLocalを使用する場合、置く。ThreadLocalの作成および初期化と同じ。ただ、終了したスレッドの子スレッドを使用して、現在の親スレッドinheritableThreadLocalsは子スレッドに転送されます。これは、子スレッドで親スレッドを使用します。データの。

プロモーターは、子スレッドにinheritableThreadLocal 24を通過する際にそのような上記の場合のように、値24がメインスレッド、スレッド内のメインスレッドinheritableThreadLocalに設けられています。そして、その後、子スレッドそれinheritableThreadLocal(既存の24の初期値)は、オペレーションを蓄積しない、そして最後には1024を取得します

おすすめ

転載: www.cnblogs.com/one-reader/p/11329675.html