最も明白な例は、スレッド ローカル ストレージの使用です。以下の例を参照してください。
class SomeClass {
// This map needs to be thread-safe
private static final Map<Thread,UnsafeStuff> map = new ConcurrentHashMap<>();
void calledByMultipleThreads(){
UnsafeStuff mystuff = map.get(Thread.currentThread());
if (mystuff == null){
map.put(Thread.currentThread(),new UnsafeStuff());
return;
}else{
mystuff.modifySomeStuff();
}
}
}
オブジェクト自体は、実行時にマップのメソッドに渡す代わりに他のスレッドを渡すと、他のスレッドに属するオブジェクトを取得するUnsafeStuff
という意味で、他のスレッドと「共有できます」 。しかし、あなたはそうしないことを選択しています。これが「スレッドに限定された使い方」です。つまり、実行時の条件は、オブジェクトが異なるスレッド間で実際に共有されないようになっているということです。 Thread.currentThread()
get
一方、以下の例では、オブジェクトは自動的にスレッドに限定され、いわば「オブジェクト自体」がスレッドに限定されます。これは、実行時の状態に関係なく、他のスレッドから参照を取得できないという意味です。
class SomeClass {
void calledByMultipleThreads(){
UnsafeStuff mystuff = new UnsafeStuff();
mystuff.modifySomeStuff();
System.out.println(mystuff.toString());
}
}
ここで、UnsafeStuff
はメソッド内で割り当てられ、メソッドが戻るとスコープ外になります。つまり、Java 仕様は、オブジェクトが常に 1 つのスレッドに限定されることを静的に保証します。したがって、制限を保証するの はランタイム条件や使用方法ではなく、Java 仕様です。
実際、最新の JVM は、最初の例とは異なり、そのようなオブジェクトをスタックに割り当てることがあります (個人的には確認していませんが、少なくとも現在の JVM ではそうではないと思います)。
しかし、言い換えれば、最初の例では、JVM はオブジェクトがスレッド内に閉じ込められているかどうかを確認することができませcalledByMultipleThreads()
んSomeClass.map
。後者の例では、それが可能です。
編集:しかし、オブジェクトを別のスレッドと共有したい場合はどうすればよいですか? スレッド A がオブジェクト O の処理を終えた後、スレッド B が O にアクセスしたいとします。
この場合は「閉じ込められた」とは呼ばないと思います。これを行うと、オブジェクトが同時にアクセスされないようにするだけです。これが、EJB 並行処理のしくみです。問題の共有オブジェクトをスレッドに「安全に公開」する必要があります。