面接の質問: ThreadLocal の理解について話す

目的

学習記録、面接対策

リソース

Station B での高頻度の面接質問に関する学習ビデオ

核となる結論

スレッド間のリソースの分離、スレッド内のリソースの共有。

原理

各スレッドには、リソース オブジェクトを格納するために使用される 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 で再利用できません。

参照リソース

メモリリークの問題

ThreadLocal メモリ リーク

ThreadLocals の添え字の計算

特別な定数 0x61c88647
0x61c88647

ソースコード分析

ソースコードウォーク

Guess you like

Origin blog.csdn.net/xiaozhengN/article/details/128078727