Per-thread instances

Let's assume that we have a single-thread application that uses a global variable of the StringBuilder type. In order to transform the application in a multithreaded application, we have to deal with StringBuilder, which is not thread-safe. Basically, we have several approaches such as synchronization and StringBuffer or other approaches. However, we can use ThreadLocal as well. The main idea here is to provide a separate StringBuilder to each thread. Using ThreadLocal, we can do it as follows:

private static final ThreadLocal<StringBuilder> 
threadLocal = new ThreadLocal<>() {

@Override
protected StringBuilder initialValue() {
return new StringBuilder("ThreadSafe ");
}
};

The current thread's initial value for this thread-local variable is set via the initialValue() method. In Java 8, this can be re-written via withInitial() as follows:

private static final ThreadLocal<StringBuilder> threadLocal 
= ThreadLocal.<StringBuilder> withInitial(() -> {

return new StringBuilder("Thread-safe ");
});

Working with ThreadLocal is done using get() and set(). Every call of set() stores the given value in a memory region that only the current thread has access to. Later on, calling get() will retrieve the value from this region. In addition, once the job is done, it is advisable to avoid memory leaks by calling the remove() or set(null) methods on the ThreadLocal instance.

Let's see a ThreadLocal at work using a Runnable:

public class ThreadSafeStringBuilder implements Runnable {

private static final Logger logger =
Logger.getLogger(ThreadSafeStringBuilder.class.getName());
private static final Random rnd = new Random();

private static final ThreadLocal<StringBuilder> threadLocal
= ThreadLocal.<StringBuilder> withInitial(() -> {

return new StringBuilder("Thread-safe ");
});

@Override
public void run() {
logger.info(() -> "-> " + Thread.currentThread().getName()
+ " [" + threadLocal.get() + "]");

Thread.sleep(rnd.nextInt(2000));

// threadLocal.set(new StringBuilder(
// Thread.currentThread().getName()));
threadLocal.get().append(Thread.currentThread().getName());

logger.info(() -> "-> " + Thread.currentThread().getName()
+ " [" + threadLocal.get() + "]");

threadLocal.set(null);
// threadLocal.remove();

logger.info(() -> "-> " + Thread.currentThread().getName()
+ " [" + threadLocal.get() + "]");
}
}

And, let's test it using several threads:

ThreadSafeStringBuilder threadSafe = new ThreadSafeStringBuilder();

for (int i = 0; i < 3; i++) {
new Thread(threadSafe, "thread-" + i).start();
}

The output reveals that each thread accesses its own StringBuilder:

[14:26:39] [INFO] -> thread-1 [Thread-safe ]
[14:26:39] [INFO] -> thread-0 [Thread-safe ]
[14:26:39] [INFO] -> thread-2 [Thread-safe ]
[14:26:40] [INFO] -> thread-0 [Thread-safe thread-0]
[14:26:40] [INFO] -> thread-0 [null]
[14:26:41] [INFO] -> thread-1 [Thread-safe thread-1]
[14:26:41] [INFO] -> thread-1 [null]
[14:26:41] [INFO] -> thread-2 [Thread-safe thread-2]
[14:26:41] [INFO] -> thread-2 [null]
In scenarios such as the preceding one, ExecutorService can be used as well.

Here is another snippet of code that provides a JDBC Connection to each thread:

private static final ThreadLocal<Connection> connections 
= ThreadLocal.<Connection> withInitial(() -> {

try {
return DriverManager.getConnection("jdbc:mysql://...");
} catch (SQLException ex) {
throw new RuntimeException("Connection acquisition failed!", ex);
}
});

public static Connection getConnection() {
return connections.get();
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.218.69