Concurrent Programming Fundamentals — Sharing Objects (Part 2)

Gowthamy Vaseekaran
6 min readMar 11, 2021

Before starting this blog, This is the continuation of my previous blog. if you have missed part 1 of this blog, Please refer to this link.

2. Publication and escape

Publishing an object means that the object can be utilized in outside the current scope.

For eg, save a reference to the object where it can be accessed by other code, or return the reference in a non-private method, or pass the reference to a method in another class.

In many cases, we want to assure that the object and its internal state are not published. In other scenarios, we need to publish an object, but if you want to ensure thread safety when publishing, you may need to synchronize.

Publishing internal states may affect and destroy encapsulation and make it difficult for programs to maintain invariant conditions. For example, if the object is released before the object is constructed, thread safety will be violated.

Escaped means that an object that should not be released is released.

The easiest approach to publish an object is to preserve the object’s reference to a public static variable so that any class and thread can see the object.

When an object is published, other objects may be published indirectly (Publishing one object may indirectly publish others.).

If you add a Secret object to the already published collection knownSecrets, then the Secret object will also be published, because any code can traverse the collection and obtain a reference to the new Secret object.

public class UnsafeStates {
private String [] states = new String [] {"AK", "AL", ...};
public String [] getStates () {return states;}
}

When an object is published, any objects referenced in the non-private domain of the object are also published. Generally speaking, if a published object can be called to other objects through non-private variable references and methods, then these objects will also be published.

Regardless of what other threads will do with the published reference, it doesn’t really matter, because the risk of misusing the reference is always there. When an object escapes, you must assume that a class or thread may misuse the object. This is the most important reason for encapsulation: encapsulation makes it possible to analyze the correctness of the program and makes it harder to inadvertently violate design constraints.

The last mechanism to publish an object or its internal state is to publish an internal class instance.

public class ThisEscape {

public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
//doSomething
}
}
);
}

}

ThisEscape class elaborates an important unique case of escape — when the this references escapes during construction. When the inner EventListener instance is published, so is the enclosing ThisEscape instance.

But an object is in a predictable, consistent state only after its constructor returns, so publishing an object from within its constructor can publish an incompletely constructed object.

This is true even if the publication is the last statement in the constructor. If the this reference escapes during construction, the object is considered not properly constructed.

Do not allow the this reference to escape during construction.

3. Thread confinement

Most of the concurrency issues happen only when we want to share a mutable variable, or mutable state, within threads.

If a mutable state is shared between multiple or several threads, then all of them will be able to read and modify the value of state, so that, resulting in incorrect or unexpected behavior.

One way to avoid this issue is to simply not share the data between the threads. This approach is known as thread confinement, and is one of the simplest approaches of achieving thread safety in our application.

Java does not have any approach of enforcing thread confinement. Thread confinement is accomplish by designing your java application 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,

  • Ad-hoc thread confinement
  • Stack confinement
  • ThreadLocal

Ad-hoc Thread Confinement

Ad-hoc thread confinement elaborates a approach of thread confinement, where it is the total responsibility of the developer, or the team of developers working on that program, to assure 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 assure that the volatile variable is only written from a single thread.

In this scenario, you are confining the modification to a single thread to prevent race conditions, and the visibility guarantees for volatile variables assure that other threads see the most up to date latest 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, since 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 method:

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

In the above method, 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 numberOfPeopleNamedGowthamy 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.

It’s better, if we document or comment when defining this variable, since 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 let 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 java application –

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. In the next blog lets discuss about Immutability.

I hope this blog was helpful for you and you got to learn something new.

Thanks and happy learning :)

--

--

Gowthamy Vaseekaran

Senior Software Engineer @ hSenid Mobile | Former Software Engineering Intern @ WSO2 | Software Engineering Undergraduate @ IIT