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