この記事では主に、ThreadLocal ローカル スレッドと Java の同期メカニズムの比較に関する関連情報を紹介します。必要な方は、
ThreadLocal
の設計を参照してください。まず、ThreadLocal の インターフェース を見てください。 :
Object get() ; // 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值 void set(Object value); // 设置当前线程的线程局部变量副本的值
ThreadLocal メソッドは 3 つありますが、最も注目に値するのは、initialValue() です。これは保護されたメソッドであり、明らかにサブクラスの書き換え専用に実装されています。このメソッドは、スレッド内の現在のスレッドのローカル変数の初期値を返します。このメソッドは、スレッドが初めて get() または set(Object) を呼び出したときに実行され、1 回だけ実行される遅延呼び出しメソッドです。 ThreadLocal の実際の実装は、null を直接返します:
protected Object initialValue() { return null; }
ThreadLocal は各スレッドの変数のコピーをどのように維持するのでしょうか?実際、実装のアイデアは非常に単純です。ThreadLocal クラスには、各スレッドの変数のコピーを保存するために使用される Map があります。
たとえば、次の実装例: これは、ThreadLocal の get メソッドの実装です
public T get() { Thread t = Thread.currentThread();//获取当前线程 ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
ThreadLocal と他の同期メカニズムの比較
ThreadLocal と他の同期メカニズムとの比較は? ThreadLocal およびその他すべての同期メカニズムは、複数のスレッドでの同じ変数へのアクセスの競合を解決するように設計されています。通常の同期メカニズムでは、複数のスレッドによる同じ変数への安全なアクセスを実現するためにオブジェクト ロックが使用されます。このとき、変数は複数のスレッドで共有されます。この同期メカニズムを使用するには、変数の読み取りと書き込みのタイミング、オブジェクトのロックのタイミング、オブジェクトのロックの解放のタイミングなどを非常に詳細に分析する必要があります。これらはすべて、複数のスレッドがリソースを共有することが原因で発生します。 ThreadLocal は、別の角度から複数のスレッドの同時アクセスを解決します。ThreadLocal は、スレッドごとにスレッドにバインドされた変数のコピーを保持するため、各スレッドの独自の変数のコピーが存在します。変数を同期する必要はありません。 ThreadLocal は、スレッドセーフな共有オブジェクトを提供します。マルチスレッド コードを作成する場合、安全でない変数全体を ThreadLocal にカプセル化することも、オブジェクトのスレッド固有の状態を ThreadLocal にカプセル化することもできます。
ThreadLocal は任意の型のオブジェクトを保持できるため、ThreadLocal を使用して現在のスレッドの値を取得するには、強制的な 型変換 が必要です。しかし、新しい Java バージョン (1.5) でのテンプレートの導入により、テンプレート パラメーターをサポートする新しい ThreadLocal
概要
もちろん、ThreadLocal は同期メカニズムを置き換えることはできず、2 つの問題領域は異なります。同期メカニズムは、複数のスレッドによる同じリソースへの同時アクセスを同期するものであり、複数のスレッド間で通信する効果的な方法です。ThreadLocal は、複数のスレッドのデータ共有を分離するものであり、複数のスレッドのリソース (変数) は基本的に共有されません。したがって、もちろん、複数のスレッドを同期する必要はありません。したがって、複数のスレッド間で通信する必要がある場合は、同期メカニズムを使用します。複数のスレッド間の共有の競合を分離する必要がある場合は、ThreadLocal を使用すると、プログラムが大幅に簡素化され、読みやすく簡潔になります。
ThreadLocal常用:
現前セッション用户
存続放散コンテキスト量、例えばウェブワークのActionContext
存放セッション、例えばSpring Hibernate ormのセッション
例:用ThreadLocal实现每線程シングルトン
スレッドローカル変数は、安全でない変数全体を ThreadLocal にカプセル化するか、オブジェクトのスレッド固有の状態を ThreadLocal にカプセル化することによって、ステートフルな「シングルトン」またはスレッドセーフな共有オブジェクトを記述するためによく使用されます。たとえば、データベースと密接な関係があるアプリケーションでは、プログラムのメソッドの多くがデータベースにアクセスする必要がある場合があります。システムのすべてのメソッドにパラメータとして Connection を含めるのは不便です。接続にアクセスするために「モナド」を使用するほうがおそらく粗雑ではありますが、はるかに便利な手法です。ただし、複数のスレッドが JDBC 接続を安全に共有することはできません。リスト 3 に示すように、「モナド」で ThreadLocal を使用すると、プログラム内のどのクラスでもスレッドごとの接続への参照を簡単に取得できるようになります。このように、ThreadLocal を使用するとスレッドごとのモナドを作成できると考えることができます。
package org.heinrich.app.connection; import java.sql.Connection; public class ConnectionUtils { private final static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); public Connection getConnection(){ Connection connection = threadLocal.get(); if(connection ==null){ connection = new DBHelper().getConn(); threadLocal.set(connection); } return connection; } } package org.heinrich.app.connection; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; //数据库连接 public class DBHelper { public static final String url = "jdbc:mysql://localhost:3306/fk_test"; public static final String name = "com.mysql.jdbc.Driver"; public static final String user = "root"; public static final String password = "root"; public Connection conn = null; public Connection getConn() { try { Class.forName(name);// 指定连接类型 conn = DriverManager.getConnection(url, user, password);// 获取连接 } catch (Exception e) { e.printStackTrace(); } return conn; } }
MySQL 接続のスレッドセーフを実装する簡単な方法
理論的に言えば、ThreadLocal は実際に各スレッドに相対的であり、各スレッドは独自の ThreadLocal を持ちます。ただし、前述したように、一般的なアプリケーション サーバーは一連のスレッド プールを維持します。したがって、異なるユーザーによるアクセスが同じスレッドを受信する可能性があります。したがって、TheadLocal に基づいて実行する場合は、ThreadLocal 変数の キャッシュ を避けるように注意する必要があります。これにより、他のスレッドがこのスレッドの変数にアクセスすることになります。
以上がJavaのローカルスレッドThreadLocalと同期機構の比較例を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。