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を取得します