Thread Confinement
Asked Answered
K

8

45

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

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?

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).

Kagera answered 7/6, 2011 at 7:28 Comment(0)
A
51

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 avoid leaking references, such as the ThreadLocal class, but nothing that ensures that no reference is leaked anywhere.

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

Similarly, if the only reference 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 Connection object from a connection pool is a good example).

Proving that 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 single thread 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".

Angulo answered 7/6, 2011 at 7:35 Comment(3)
"There's no language- or JVM-level mechanism that confines an object to a single thread" => What about ThreadLocal as long as you don't escape explicitely the reference elsewhere?Pinchas
@ThreadLocal doesn't ensure that the reference is confined to a single thread. It just avoids leaking it through this reference. You can still easily leak it in other ways.Angulo
You could make a 'proxy' object (possibly with the help of a InvocationHandler) and validate Thread.currentThread() == YOUR_THREAD at each method call. But you would have to do this recursively down your object tree to be 100% sure though...Harvard
E
13

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 UnsafeStuff objects 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 get method, 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 runtime conditions are such that the objects is in effect never shared between different threads.

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 UnsafeStuff is 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 it that is ensuring the confinement, but more the Java spec.

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).

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.


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?

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.

Extrados answered 7/6, 2011 at 7:55 Comment(0)
H
6

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.
Haller answered 7/6, 2011 at 7:36 Comment(2)
While your answer is surely correct, the OP is not the only one to be confused by the book text. If the object is 'confined' as you say, eg. its only reference is on the stack of the thread and its reference is never signaled off the thread, then its pretty obvious that that thread is the only one that can possibly access the object. The book text implies that there is some special locking mechanism available, eg 'myThread.confine(myObject)', rather than 'normal' language constraints.Autostability
@Martin James - I have the book text in front of me. If you read the quoted sentence in context it is not at all unclear. There is certainly no implication of any special mechanism to achieve confinement.Haller
F
5

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

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)

Fong answered 7/6, 2011 at 7:36 Comment(0)
C
3

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 list is 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.

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 ThreadLocal variable which allows each thread to have its own copy. In the example below, each thread will have its own DateFormat object and so you don't need to worry about the fact that DateFormat is not thread-safe because it won't be accessed by multiple threads.

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

Further Reading

Cubital answered 7/6, 2011 at 7:41 Comment(0)
C
0

See: 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.

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)

Chassidychassin answered 7/6, 2011 at 7:35 Comment(4)
Note that storing a reference to an object in a ThreadLocal does not ensure that the object will be confined to that thread. You can still easily leak the object to other threads via different means.Angulo
Add to that, ThreadLocal is most useful when you have a bunch of threads doing the same thing. If you have one thread that has unique stuff meant just for it, ThreadLocal is nearly useless.Boulevard
It's a pity I cannot vote up cHao comment:) In decades of multiThreaded development I have never used, or been tempted to use, any ThreadLocal storage. The thread stack IS thread-local storage. In an OO language, private data members of the thread class also seem pretty 'thread-local' to me :)Autostability
@Martin James - ThreadLocale is useful when you need to pass an object through the stack, but don't want to muddy up the methods. For example, your DAO might put a db connection into thread local so that it doesn't have to pass the db connection around to all the methods responsible for loading a response.Sukiyaki
P
0

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

Pinchas answered 7/6, 2011 at 7:36 Comment(0)
S
0

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"

Spiroid answered 7/6, 2011 at 7:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.