目次
目的
学習記録、面接対策
リソース
核となる結論
スレッド間のリソースの分離、スレッド内のリソースの共有。
原理
各スレッドには、リソース オブジェクトを格納するために使用される ThreadLocalMap 型のメンバー変数があります。
① set() を呼び出します。つまり、ThreadLocal 自体をキーとして、リソース オブジェクトを値として使用し、現在のスレッドの ThreadLocalMapに格納します
。 ② 呼び出しget()、つまり ThreadLocal 自体をキーとして使用し、現在のスレッドで関連付けられたリソース値を検索します。
③ Remove() を呼び出します。つまり、ThreadLocal 自体をキーとして使用して、現在のスレッドに関連付けられたリソース値を削除します。
コードデモ
/**
* TestThreadLocal: 线程之间资源隔离, 线程内资源共享
*
* @author xiaozhengN [email protected]
* @since 2022-11-27 22:12:39
**/
@Slf4j
public class TestThreadLocal {
public static void main(String[] args) {
test1();
test2();
}
/**
* 多个线程调用, 得到的是自己的Connection对象
*/
private static void test1() {
for (int i = 0; i < 5; i++) {
new Thread(() -> log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection()), "test1Thread" + (i + 1)).start();
}
}
/**
* 一个线程内调用, 得到的是同一个Connection对象
*/
private static void test2() {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection());
log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection());
}, "test2Thread" + (i + 1)).start();
}
}
static class Utils {
// 线程隔离
private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
/**
* 获取连接
*
* @return Connection对象
*/
public static Connection getConnection() {
Connection connection = threadLocal.get();
if (connection == null) {
connection = innerGetConnection();
threadLocal.set(connection);
}
return connection;
}
private static Connection innerGetConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/bos?useSSL=false", "root", "root");
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
他の
ThreadLocalMap のキーを弱参照として設計する必要がある理由
① スレッドは長時間実行する必要がある場合があります (スレッド プール内のスレッドなど)、キーが使用されなくなった場合は、GC によってリサイクルする必要があります ② ただし、GC はキーのメモリを解放するだけで、その後
さらにキーが null かどうかに応じて値を解放します。 メモリを解放する時間は次のとおりです。
2.1 キーを取得し、null キーを見つけます
。 2.2 キーを設定するときに、ヒューリスティック スキャンを使用して、隣接する null キーの数をクリアします。ヒューリスティックは要素の数と null キーを見つけるかどうかに関係します
2.3 削除する場合 (推奨)、一般に ThreadLocal を使用する場合、静的変数として使用されるため、GC で再利用できません。
参照リソース
メモリリークの問題
ThreadLocals の添え字の計算
特別な定数 0x61c88647
0x61c88647