ThreadLocalの実装を読むとわかるのですが、実はThreadLocalの各メソッドを通して
Thread.currentThread()のメンバ変数threadlocalsというマップにアクセスしています。
(threadlocalsはパッケージプライベートなので、同じパッケージに属するThreadLocalからではないとアクセスできません)
ですので、グローバルなマップのようなものにアクセスしているわけではなく、
処理中のスレッドのメンバーにアクセスしているため、スレッドごとに違う値になるのは自明ですね。
ちなみにスレッドの生成コストは意外と高く、
マルチスレッドが予想されるようなアプリケーションではそれらをプールして使いまわすのが一般的です。
スレッドが使いまわされるケースでThreadLocalを使用する場合は注意が必要です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。