AndroidはすごいThreadLocalの動作原理と実例分析

5905 ワード

ThreadLocalの紹介
   ThreadLocalは単純に字面から理解すると「ローカルスレッド」の意味のようですが、実はそういう意味ではなく、ただこの名前が誤解されやすいだけで、その本当の意味はスレッドローカル変数です.公式にどう言っているか見てみましょう.
1つのスレッドのローカルストレージを実現します.すなわち、各スレッドには独自のローカル変数があります.すべてのスレッドはThreadLocalオブジェクトを共有していますが、各スレッドはこれらの変数にアクセスすると異なる値を得ることができ、各スレッドはこれらの変数を変更することができ、他のスレッドに影響を与えることなくnull値をサポートします.
private ThreadLocalmBooleanThreadLocal = new ThreadLocal();
public void testThreadLocal(){
    mBooleanThreadLocal.set(true);
    Log.d(TAG, "[Thread#main]mBooleanThreadLocal=" + mBooleanThreadLocal.get());

    new Thread("Thread#1") {
        @Override
        public void run() {
            mBooleanThreadLocal.set(false);
            Log.d(TAG, "[Thread#1]mBooleanThreadLocal=" + mBooleanThreadLocal.get());
        };
    }.start();

    new Thread("Thread#2") {
        @Override
        public void run() {
            Log.d(TAG, "[Thread#2]mBooleanThreadLocal=" + mBooleanThreadLocal.get());
        };
    }.start();
}

上記のコードでは、メインスレッドにmBooleanThreadLocalの値をtrue、サブスレッド1にmBooleanThreadLocalの値をfalse、サブスレッド2にmBooleanThreadLocalの値を設定せず、それぞれ3つのスレッドでgetメソッドでmBooleanThreadLocalの値を除去し、前述のThreadLocalの説明によれば、この場合、メインスレッドではtrue、サブスレッド1はfalseであるべきであり、サブスレッド2では値が設定されていないためnullであるべきであり、プログラムをインストールして実行し、ログは以下の通りである.
D/TestActivity(8676):[Thread#main]mBooleanThreadLocal=true
D/TestActivity(8676):[Thread#1]mBooleanThreadLocal=false
D/TestActivity(8676):[Thread#2]mBooleanThreadLocal=nullまとめ:
ThreadLocalは共有変数の問題を解決するために用いられるものではなく,スレッドの同期を調整するために存在するものではなく,各スレッドが自分の状態を処理するのを容易にするために導入されたメカニズムである.
したがって、ThreadLocalは、共有マルチスレッドへのアクセスの問題を解決するためではなく、スレッド同期の問題を解決するためでもありません.ThreadLocalの設計の目的は、スレッド内部の局所変数を提供し、本スレッド内でいつでもどこでも読み取りやすくし、他のスレッドから隔離することです.
Android 2には
1).Androidのメッセージメカニズムは主にHandlerの実行メカニズムを指す
一般に、あるデータがスレッドを役割ドメインとし、異なるスレッドが異なるデータコピーを有する場合、ThreadLocalを採用することが考えられる.例えばHandlerの場合、現在のスレッドのLooperを取得する必要があります.Looperの役割ドメインはスレッドであり、異なるスレッドは異なるLooperを有していることは明らかです.
2).オープンソースフレームワークEventBusは,現在のスレッドにおける送信イベントキューの状態もThreadLocalを採用する.
ThreadLocal使用シーン
1.あるデータがスレッドを役割ドメインとし、異なるスレッドが異なるデータコピーを持つ場合.
   ThreadLocalの使用状況は,マルチスレッドにおけるデータの同時発生による不一致の問題を主に解決する.ThreadLocalは空間で時間を変えて、各スレッドの中で同時にアクセスするデータにコピーを提供して、コピーにアクセスして業務を実行して、このような結果はメモリを消耗して、しかしスレッドの同期によるスレッドの消耗を大幅に減らして、スレッドの同時制御の複雑さも減らしました.
   例えばAndroidのHandlerメッセージメカニズムは、Handlerにとって現在のスレッドを取得するlooperが必要であることは明らかであり、Looperの役割ドメインはスレッドであり、異なるスレッドには異なるLooperがあり、このときThreadLocalによって簡単にLooperのスレッドへのアクセスを実現することができる.例えばオープンソースフレームワークEventBusでは、EventBusは現在のスレッドのPostingThreadStateオブジェクトを取得する必要があり、異なるPostingThreadStateは同じように異なるスレッドに作用し、EventBusは現在のスレッドの下のPostingThreadStateオブジェクトを簡単に取得し、関連操作を行うことができます.
2)複雑な論理の下でのオブジェクトの伝達、例えばリスナーの伝達
   パラメータ伝達を使用すると、関数呼び出しスタックがより深くなると、設計が悪くなり、スレッドごとに静的変数リスナーを定義します.マルチスレッドであれば、1つのスレッドに静的変数を定義する必要があり、拡張できません.この場合、ThreadLocalを使用して問題を解決できます.原理:同等
ConcurrentMap、それより良くて、安全です
使用者の観点から、一般的にThreadLocalは、このスレッドのローカル変数を保存するためにThread参照をkeyとしてConcurrentHashMapと見なすことができます.しかし、実現の観点から言えば、ThreadLocalの実現はまったくそうではない.次に、ソースコードからThreadLocalの実装を分析する.
setメソッド:Mapでスレッドをバインドする
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メソッド:キーで値を取得する
ASコードアドレス: