最明显的例子是使用线程本地存储。请参阅下面的示例:
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());
}
}
此处,在方法内分配,并在方法返回时超出范围。换句话说,Java 规范静态地确保对象始终局限于一个线程。因此,确保限制的不是运行时条件或使用它的方式,而是Java规范。UnsafeStuff
事实上,现代JVM有时会在堆栈上分配这样的对象,这与第一个例子不同(没有亲自检查过,但我认为至少当前的JVM没有这样做)。
换句话说,在第一个例子中,JVM不能通过查看内部来确定对象是否被限制在线程内(谁知道其他方法正在搞砸什么)。在后一个例子中,它可以。calledByMultipleThreads()
SomeClass.map
编辑:但是,如果我仍然想与另一个线程共享对象怎么办?假设线程 A 完成对象 O 后,线程 B 想要访问 O。在这种情况下,在A完成之后,O还能被限制在B中吗?
我不认为在这种情况下它被称为“受限”。执行此操作时,您只是确保不会同时访问对象。这就是 EJB 并发的工作原理。您仍然必须将有问题的共享对象“安全地发布”到线程。