java 线程限制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6261910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 15:05:04  来源:igfitidea点击:

Thread Confinement

javamultithreadingconcurrencythread-safetythread-confinement

提问by denniss

I am reading Java Concurrency in Practice and kind of confused with the thread confinement concept. The book says that

我正在阅读 Java Concurrency in Practice 并且对线程限制概念有些困惑。书上说

When an object is confined to a thread, such usage is automatically thread-safe even if the confined object itself is not

当一个对象被限制在一个线程中时,这种用法自动是线程安全的,即使被限制的对象本身不是

So when an object is confined to a thread, no other thread can have access to it? Is that what it means to be confined to a thread? How does one keep an object confined to a thread?

那么当一个对象被限制在一个线程中时,没有其他线程可以访问它吗?这就是被限制在一个线程中的意思吗?如何将对象限制在线程中?

Edit:But what if I still want to share the object with another thread? Let's say that after thread A finishes with object O, thread B wants to access O. In this case, can O still be confined to B after A is done with it?

编辑:但是如果我仍然想与另一个线程共享对象怎么办?假设线程A处理完对象O后,线程B想要访问O。在这种情况下,A处理完后O还可以限制在B中吗?

Using a local variable is one example for sure but that just means you don't share your object with other thread (AT ALL). In case of JDBC Connection pool, doesn't it pass one connection from one thread to another once a thread is done with that connection (totally clueless about this because I never used JDBC).

使用局部变量肯定是一个例子,但这只是意味着您不与其他线程共享您的对象(完全)。在 JDBC 连接池的情况下,一旦一个线程完成了该连接,它是否不会将一个连接从一个线程传递到另一个线程(对此完全一无所知,因为我从未使用过 JDBC)。

回答by Joachim Sauer

So when an object is confined to a thread, no other thread can have access to it?

那么当一个对象被限制在一个线程中时,没有其他线程可以访问它吗?

No, it's the other way around: if you ensure that no other thread has access to an object, then that object is said to be confined to a single thread.

不,恰恰相反:如果您确保没有其他线程可以访问某个对象,那么该对象就被称为仅限于单个线程。

There's no language- or JVM-level mechanism that confines an object to a single thread. You simply have to ensure that no reference to the object escapes to a place that could be accessed by another thread. There are tools that help avoidleaking references, such as the ThreadLocalclass, but nothing that ensuresthat no reference is leaked anywhere.

没有将对象限制为单个线程的语言或 JVM 级机制。您只需要确保没有对对象的引用逃逸到另一个线程可以访问的地方。有一些工具可以帮助避免泄漏引用,例如ThreadLocal类,但没有任何工具可以确保任何地方都没有引用泄漏。

For example: if the onlyreference to an object is from a local variable, then the object is definitelyconfined to a single thread, as other threads can never access local variables.

例如:如果对一个对象的唯一引用来自一个局部变量,那么该对象肯定被限制在一个线程中,因为其他线程永远不能访问局部变量。

Similarly, if the onlyreference to an object is from another object that has already been proven to be confined to a single thread, then that first object is confined to the same thread.

类似地,如果对一个对象的唯一引用来自另一个已被证明仅限于单个线程的对象,则该第一个对象仅限于同一线程。

Ad Edit:In practice you can have an object that's only accessed by a single thread at a time during its lifetime, but for which that single thread changes (a JDBC Connectionobject from a connection pool is a good example).

广告编辑:在实践中,您可以拥有一个对象,该对象在其生命周期内一次只能由一个线程访问,但该单个线程会发生变化(Connection连接池中的 JDBC对象就是一个很好的例子)。

Provingthat such an object is only ever accessed by a single thread is much harder than proving it for an object that's confined to a singlethread during its entire life, however.

然而,证明这样的对象只能被单个线程访问比证明一个对象在其整个生命周期中仅限于单个线程访问要困难得多。

And in my opinion those objects are never really "confined to a single thread" (which would imply a strong guarantee), but could be said to "be used by a single thread at a time only".

在我看来,这些对象从来没有真正“局限于一个线程”(这意味着一个强有力的保证),而是可以说“一次只能由一个线程使用”。

回答by Enno Shioji

The most obvious example is use of thread local storage. See the example below:

最明显的例子是使用线程本地存储。请参阅以下示例:

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();
        }
    }
}

The UnsafeStuffobjects itself "could be shared" with other threads in the sense that if you'd pass some other thread instead of Thread.currentThread()at runtime to the map's getmethod, you'd get objects belonging to other threads. But you are choosing not to. This is "usage that is confined to a thread". In other words, the runtimeconditions are such that the objects is in effectnever shared between different threads.

UnsafeStuff自身“可共享”用在这个意义上其他线程对象,如果您想一些其他的线程,而不是通过Thread.currentThread()在运行到地图的get方法,你会得到属于其他线程对象。但你选择不这样做。这是“仅限于线程的用法”。换句话说,运行时条件使得对象实际上永远不会在不同线程之间共享。

On the other hand, in the example below the object is automatically confined to a thread, and so to say, the "object itself" is confined to the thread. This is in the sense that it is impossible to obtain reference from other threads no matter what the runtime condition is:

另一方面,在下面的例子中,对象被自动限制在一个线程中,也就是说,“对象本身”被限制在线程中。从某种意义上说,无论运行时条件如何,都不可能从其他线程获取引用:

class SomeClass {
    void calledByMultipleThreads(){
        UnsafeStuff mystuff = new UnsafeStuff();
        mystuff.modifySomeStuff();
        System.out.println(mystuff.toString());
    }
}

Here, the UnsafeStuffis allocated within the method and goes out of scope when the method returns.. In other words, the Java spec is ensuring statically that the object is always confined to one thread. So, it is not the runtime condition or the way you use itthat is ensuring the confinement, but more the Java spec.

在这里,UnsafeStuff是在方法内分配的,并在方法返回时超出范围。换句话说,Java 规范静态地确保对象始终限于一个线程。因此,确保限制的不是运行时条件或您使用它方式,而是 Java 规范。

In fact, modern JVM sometimes allocate such objects on stack, unlike the first example (haven't personally checked this, but I don't think at least current JVMs do).

事实上,现代 JVM 有时会在堆栈上分配此类对象,这与第一个示例不同(我没有亲自检查过,但我认为至少当前的 JVM 不会这样做)。

Yet in other words, in the fist example the JVM can't be sure if the object is confined within a thread by just looking inside of calledByMultipleThreads()(who knows what other methods are messing with SomeClass.map). In the latter example, it can.

然而,换句话说,在第一个示例中,JVM 无法通过查看内部来确定对象是否被限制在一个线程内calledByMultipleThreads()(谁知道其他方法正在处理什么SomeClass.map)。在后一个例子中,它可以。



Edit: But what if I still want to share the object with another thread? Let's say that after thread A finishes with object O, thread B wants to access O. In this case, can O still be confined to B after A is done with it?

编辑:但是如果我仍然想与另一个线程共享对象怎么办?假设线程A处理完对象O后,线程B想要访问O。在这种情况下,A处理完后O还可以限制在B中吗?

I don't think it is called "confined" in this case. When you do this, you are just ensuring that an object is not accessed concurrently. This is how EJB concurrency works. You still have to "safely publish" the shared object in question to the threads.

我不认为在这种情况下它被称为“受限”。当您这样做时,您只是确保不会同时访问一个对象。这就是 EJB 并发的工作原理。您仍然必须将有问题的共享对象“安全地发布”到线程。

回答by Stephen C

So when an object is confined to a thread, no other thread can have access to it?

那么当一个对象被限制在一个线程中时,没有其他线程可以访问它吗?

That's what thread confinement means - the object can only EVER be accessed by one thread.

这就是线程限制的意思——对象只能被一个线程访问。

Is that what it means to be confined to a thread?

这就是被限制在一个线程中的意思吗?

See above.

往上看。

How does one keep an object confined to a thread?

如何将对象限制在线程中?

The general principle is to not put the reference somewhere that would allow another thread to see it. It is a little bit complicated to enumerate a set of rules that will ensure this, but (for instance) if

一般原则是不要将引用放在允许另一个线程看到它的地方。列举一组确保这一点的规则有点复杂,但是(例如)如果

  • you create a new object, and
  • you never assign the object's reference to an instance or class variable, and
  • you never call a method that does this for the reference,
  • then the object will be thread confined.
  • 您创建一个新对象,并且
  • 您永远不会将对象的引用分配给实例或类变量,并且
  • 你永远不会调用一个方法来作为参考,
  • 那么对象将被线程限制。

回答by Andreas Dolk

I guess that's what want to say. Like creating a object inside the runmethod and not passing the reference to any other instance.

我想这就是想说的。就像在run方法内部创建一个对象而不是将引用传递给任何其他实例。

Simple example:

简单的例子:

public String s;

public void run() {
  StringBuilder sb = new StringBuilder();
  sb.append("Hello ").append("world");
  s = sb.toString();
}

The StringBuilder instance is thread-safe because it is confined to the thread (that executes this run method)

StringBuilder 实例是线程安全的,因为它仅限于线程(执行此 run 方法)

回答by dogbane

One way is "stack confinement" in which the object is a local variable confined to the thread's stack, so no other thread can access it. In the method below, the listis a local variable and doesn't escape from the method. The list doesn't have to be threadsafe because it is confined to the executing thread's stack. No other thread can modify it.

一种方法是“堆栈限制”,其中对象是限制在线程堆栈中的局部变量,因此其他线程无法访问它。在下面的方法中,list是一个局部变量,不会从方法中逃脱。该列表不必是线程安全的,因为它仅限于执行线程的堆栈。没有其他线程可以修改它。

public String foo(Item i, Item j){
    List<Item> list = new ArrayList<Item>();
    list.add(i);
    list.add(j);
    return list.toString();
}

Another way of confining an object to a thread is through the use of a ThreadLocalvariable which allows each thread to have its own copy. In the example below, each thread will have its own DateFormatobject and so you don't need to worry about the fact that DateFormatis not thread-safe because it won't be accessed by multiple threads.

将对象限制在线程中的另一种方法是使用ThreadLocal变量,该变量允许每个线程拥有自己的副本。在下面的示例中,每个线程都有自己的DateFormat对象,因此您无需担心DateFormat不是线程安全的事实,因为它不会被多个线程访问。

private static final ThreadLocal<DateFormat> df
                 = new ThreadLocal<DateFormat>(){
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyyMMdd");
    }
  };

Further Reading

进一步阅读

回答by Bohemian

I means that only code running in one thread accesses the object.

我的意思是只有在一个线程中运行的代码才能访问该对象。

When this is the case, the object doesn't need to be "thread safe"

在这种情况下,对象不需要是“线程安全的”

回答by dbf

See: http://codeidol.com/java/java-concurrency/Sharing-Objects/Thread-Confinement/

请参阅:http: //codeidol.com/java/java-concurrency/Sharing-Objects/Thread-Confinement/

A more formal means of maintaining thread confinement is ThreadLocal, which allows you to associate a per-thread value with a value-holding object. Thread-Local provides get and set accessormethods that maintain a separate copy of the value for each thread that uses it, so a get returns the most recent value passed to set from the currently executing thread.

维护线程限制的一种更正式的方法是 ThreadLocal,它允许您将每个线程的值与值保持对象相关联。Thread-Local 提供了 get 和 set 访问方法,它们为每个使用它的线程维护一个单独的值副本,因此 get 返回从当前执行的线程传递给 set 的最新值。

It holds a copy of object per one thread, thread A can't access copy of thread B and broke it's invariants if you will do it specially (for example, assign ThreadLocal value to static variable or expose it using other methods)

它为每个线程保存一个对象副本,线程 A 无法访问线程 B 的副本并破坏它的不变量,如果您专门这样做(例如,将 ThreadLocal 值分配给静态变量或使用其他方法公开它)

回答by Grooveek

That's exactly what it means. The object itself is accessed by only one thread, and is thus thread-safe. ThreadLocalobjects are a kind of objects that are bound to an only thread

这正是它的意思。对象本身只能被一个线程访问,因此是线程安全的。ThreadLocal对象是一种绑定到唯一线程的对象