ホームページ  >  記事  >  Java  >  Java での ThreadLocal の詳細な紹介 (コード例)

Java での ThreadLocal の詳細な紹介 (コード例)

不言
不言転載
2019-03-06 15:56:283308ブラウズ

この記事では、Java の ThreadLocal について詳しく紹介 (コード例) しています。一定の参考価値があります。必要な友人は参照してください。お役に立てば幸いです。

ThreadLocal は基本的にプロジェクト開発では使用されませんが、面接官はこの種の質問を好むため、このクラスの機能と原理を理解しておく必要があります。

ThreadLocal とは

ThreadLocal は、複数のスレッドのスレッドごとに変数の個別のコピーを作成するクラスです。ThreadLocal を使用して変数を維持する場合、ThreadLocal は、複数のスレッドによって引き起こされるデータの不整合を避けるために、スレッドごとに変数の個別のコピーを作成します。共有変数のスレッド操作;

ThreadLocal クラスはどのようなシナリオで使用されますか?

一般的に、ThreadLocal は実際の工業生産では使用されません。一般的ですが、多くのフレームワークで使用すると、いくつかのフレームワークの問題を解決できます。たとえば、Spring のトランザクション、Spring のスコープ ScopeRequest の Bean は、ThreadLocal.

## を使用して解決できます。 #ThreadLocal の使用方法

1. ThreadLocal 変数を使用して、複数のスレッドからアクセスする必要がある属性を定義します。以下は、インターネットで最も一般的に使用される DBConnectionFactory クラスの例です

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnectionFactory {

    private static final ThreadLocal<Connection> dbConnectionLocal = new ThreadLocal<Connection>() {
        @Override
        protected Connection initialValue() {
            try {
                return DriverManager.getConnection("", "", "");
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    };

    public Connection getConnection() {
        return dbConnectionLocal.get();
    }
}
このようにして、クライアントでは接続を取得するときに、各スレッドによって取得される接続はそのスレッドに固有であり、接続のスレッド分離が実現されるため、スレッドの安全性の問題は発生しません

#ThreadLocal がスレッドを実装する方法isolation

1. 主に Thread オブジェクト内の ThreadLocalMap 型変数 threadLocals を使用します。これは、現在のスレッドの Connection オブジェクトを格納する役割を担っています。dbConnectionLocal 変数はキーとして使用され、新しく作成された Connection オブジェクトはが値として使用されます。この場合、最初にスレッドが読み取られるときに存在しない場合、ThreadLocal のInitialValue メソッドが呼び出されて Connection オブジェクトが作成され、戻り値が返されます。

スレッドへの変数は次のとおりです:

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();
}

1. まず現在の Thread オブジェクト t を取得し、次にスレッド t から ThreadLocalMap のメンバー属性 threadLocals

# を取得します。現在のスレッドが初期化されており (つまり、null ではなく)、現在の ThreadLocal オブジェクトをキーとして持つ値がある場合は、現在のスレッドによって取得されるオブジェクト (この例では Connection) を直接返します。

3. 現在のスレッドの threadLocals が初期化されている (つまり、null ではない) が、現在の ThreadLocal オブジェクトをキーとして持つオブジェクトがない場合は、Connection オブジェクトを再作成し、それを threadLocals に追加します。現在のスレッドのマップを返し、

4 を返します。現在のスレッドの threadLocals プロパティが初期化されていない場合は、ThreadLocalMap オブジェクトを再作成し、Connection オブジェクトを作成して ThreadLocalMap オブジェクトに追加して返します。

存在する場合は、直接返されます。理解するのは簡単です。それでは、初期化方法のコードは何ですか?

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;
}
1. まず、作成したオーバーロードされたinitialValueメソッドを呼び出します。上記の操作により、Connection オブジェクトが生成されます。

2. 現在のスレッドの threadLocals が空かどうかの確認を続けます。ThreadLocalMap が初期化されている場合は、生成されたオブジェクトを ThreadLocalMap に直接追加します。初期化されていない場合は、 ;

同時に、ThreadLocal は Thread オブジェクト内の threadLocals を直接操作するメソッドも提供します

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
この方法では、initialValue を実装することもできません。 DBConnectionFactory の getConnection メソッドに初期化作業を追加します。

public Connection getConnection() {
    Connection connection = dbConnectionLocal.get();
    if (connection == null) {
        try {
            connection = DriverManager.getConnection("", "", "");
            dbConnectionLocal.set(connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return connection;
}
次に、コードを読むと、ThreadLocal が変数のマルチスレッド分離を実現できる理由が明確に理解できます。実際、これは Map データ構造を使用して、現在のスレッドをキャッシュし、それが使用されるときは、このスレッドからキャッシュされます。threadLocals オブジェクトから取得するだけで、キーは現在のスレッドになります。

もちろん、現在のスレッドでマップし、現在のスレッドで操作すると、スレッドの同時実行の問題はまったく発生しません。もちろん変数も使用できます。スレッドは分離されます。

ThreadLocal とは何か、そしてその方法はわかりました。 ThreadLocal とその基本的な実装原則を使用しますが、これを終了してもよいでしょうか? 実際、もう 1 つの質問があります: ThreadLocalMap とは何ですか? オブジェクト、なぜこのオブジェクトを使用するのですか?

ThreadLocalMap オブジェクトとは

本質的に言ってみれば、これは Map ですが、この ThreadLocalMap は、私たちが通常見る Map とは少し異なります

1. Map インターフェイスを実装していません;

2. これにはパブリック メソッドがありません。この ThreadLocalMap メソッドは ThreadLocal クラス内でのみ呼び出され、静的内部クラス

3 であるため、デフォルト コンストラクターは最大 1 つです。ThreadLocalMap の Entry 実装は WeakReference>

# を継承します。 ##4. このメソッドは、キーと値を保存するためにエントリ配列のみを使用します。エントリはリンク リストの形式ではなく、各バケットに 1 つのエントリだけが配置されます。

以上がJava での ThreadLocal の詳細な紹介 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。