Java Concurrency: Thread Confinement

Reading Time: 3 minutes

Hello readers! In this blog, we are going to explore about Thread Confinement, what it means and how do we achieve it. So, let’s dive straight into it.

Thread Confinement

Most of the concurrency problems occur only when we want to share a mutable variable, or mutable state, between threads. If a mutable state is shared between multiple threads, then all of them will be able to read and modify the value of state, thus resulting in incorrect or unexpected behaviour. One way to avoid this problem is to simply not share the data between the threads. This technique is known as thread confinement, and is one of the simplest ways of achieving thread safety in our application.

Java language in itself does not have any way of enforcing thread confinement. Thread confinement is achieved by designing your program in a way that does not allow your state to be used by multiple threads, and is thus enforced by the implementation. There are few types of thread confinement, as described below.

Ad-hoc Thread Confinement

Ad-hoc thread confinement describes a way of thread confinement, where it is the total responsibility of the developer, or the group of developers working on that program, to ensure that the use of the object is restricted to a single thread. This approach is very very fragile, and should be avoided in most cases.

One special case that comes under Ad-hoc thread confinement applies to volatile variables. It is safe to perform read-modify-write operations on shared volatile variable as long as you ensure that the volatile variable is only written from a single thread. In this case, you are confining the modification to a single thread to prevent race conditions, and the visibility guarantees for volatile variables ensure that other threads see the most up to date value.

Stack Confinement

Stack confinement is confining a variable, or an object, to the stack of the thread. This is much stronger than Ad-hoc thread confinement, as it is limiting the scope of the object even more, by defining the state of the variable in the stack itself. For example, consider the following piece of code –

private long numberOfPeopleNamedJohn(List<Person> people) {
List<Person> localPeople = new ArrayList<>();
localPeople.addAll(people);
return localPeople.stream().filter(person -> person.getFirstName().equals("John")).count();
}

In the above code, we pass in a list of person, but do not directly use it. We instead create our own list, which is local to the currently executing thread, and add all the person in people to localPeople. Since we are defining our list in the numberOfPeopleNamedJohn method only, this makes the variable localPeople stack confined, as it exists on stack of one thread, and thus cannot be accessed by any other thread. This makes localPeople thread safe. The only thing we need to take care of here is that we should not allow localPeople to escape the scope of this method, to keep it stack confined. This should also be documented or commented when defining this variable, as generally it’s only in the current developer’s mind to not let it escape, and in future another developer may mess up.

ThreadLocal

ThreadLocal allows you to associate a per-thread value with a value-holding object. It allows you to store different objects for different threads, and maintains which object corresponds to which thread. It has set and get accessor methods which maintain a separate copy of the value for each thread that uses it. The get() method always returns the most updated value passed to set() from the currently executing thread. Let’s look at an example –

public class ThreadConfinementUsingThreadLocal {
public static void main(String[] args) {
ThreadLocal<String> stringHolder = new ThreadLocal<>();
Runnable runnable1 = () -> {
stringHolder.set("Thread in runnable1");
try {
Thread.sleep(5000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable runnable2 = () -> {
stringHolder.set("Thread in runnable2");
try {
Thread.sleep(2000);
stringHolder.set("string in runnable2 changed");
Thread.sleep(2000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable runnable3 = () -> {
stringHolder.set("Thread in runnable3");
try {
Thread.sleep(5000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);
Thread thread3 = new Thread(runnable3);
thread1.start();
thread2.start();
thread3.start();
}
}

In the above example, we have executed three threads, using the same ThreadLocal object stringHolder. As you can see here, we have, first of all, set one string in every thread in the stringHolder object, making it contain three strings. Then after some pause, we have changed the value from just the second thread. Below was the output of the program –

string in runnable2 changed
Thread in runnable1
Thread in runnable3

As you can see in the above output, the String for thread 2 changed, but the strings for thread 1 and thread 3 were unaffected. If we do not set any value before getting the value on a specific thread from ThreadLocal, then it returns null. After a thread is terminated, thread-specific objects in ThreadLocal become ready for garbage collection.

That is all about thread confinement. I hope this blog was helpful for you and you got to learn something new. Thanks and happy blogging!

Written by 

Akshansh Jain is a Software Consultant having more than 1 year of experience. He is familiar with Java but also has knowledge of various other programming languages such as scala, HTML and C++. He is also familiar with different Web Technologies and Android programming. He is a passionate programmer and always eager to learn new technologies & apply them in respective projects.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading