Thread Synchronization Utilities

We talk about synchronization when more than one concurrent task shares a resource.

The blocks of code that access this shared resource are called critical sections.

The high-level mechanisms are:

  • Semaphores: A semaphore is a counter that controls the access to one or more shared resources.
  • CountDownLatch: The CountDowLatch class is a mechanism provided by the Java language that allows a thread to wait for the finalization of multiple operations.
  • CyclicBarrier: The CyclicBarrier class is another mechanism provided by the Java language that allows the synchronization of multiple threads in a common point.
  • Phaser: The Phaser class is another mechanism provided by the Java language that controls the execution of concurrent tasks divided in phases. All the threads must finish one phase before they can continue with the next one.
  • Exchanger: The Exchanger class is another mechanism provided by the Java language that provides a point of data interchange between two threads.

Controlling concurrent access to a resource

A semaphore is a counter taht protects the access to one or more shared resources.

When a thread wants to access one of these shared resources, first, it must acquire that semaphore. If the internal counter of the semaphore is greater than 0, the semaphore decrements the counter and allows access to the shared resource. A counter bigger than 0 means there are free resources that can be used, so the thread can access and use one of them.

When the thread has finished the use of the shared resource, it must release the semaphore so that the other thread can access the shared resource. That operation increases the internal counter of the semaphore.

Binary semaphores protect the access to a unique shared resource, so the internal counter of the semaphore can only take the values of 1 or 0.

Fairness in semaphores

The default mode is called the non-fair mode. In this mode, when the synchronization resources is released, one of the waiting threads is selected to get this resource, but it's selected without any criteria. The fair mode changes this behavior and forces to select the thread that has been waiting for more time.

The Semaphore class admits a second parameter in its constructor. This parameter must take a Boolean value. If you give it the false value, you are creating a semaphore that will work in non-fair mode. You will get the same behavior if you don't use this parameter.

Controlling concurrent access to multiple copies of a resource

2016/4/13 posted in  Java7 Concurrency Cookbook

Basic Thread Synchronization

Introduction

In a concurrent application, it is normal that multiple threads read or write the same data or have access to the same file or database connection.

The solution for these problems comes with the concept of critical section.

A critical section is a block of code that accesses a shared resource and can't be executed by more than one thread at the same time.

When a thread wants access to a critical section, it uses one of those synchronization mechanisms to find out if there is any other thread executing the critical section. Otherwise, the thread is suspended by the sunchronization mechanism until the thread that is executing the critical section ends it.

Synchronizing a method

the use of the synchronized keyword to control the concurrent access to a method.

Only one execution thread will access one of the methods of an object declared with the synchronized keyword. If another thread tries to access any method declared with the synchronized keyword of the same object, it will suspended until the first thread finishes the execution of the method.

Static methods have a different behavior. Only one execution thread will access one of the static methods declared with the synchronized keyword, but another thread can access other non-static methods of an object of that class.

Two threads can access two different synchronized methods if one is static and the other one is not.

Only a thread can access the methods of an object that use the sychronized keyword in their declaration. If a thread(A) is executing a synchronized method and another thread(B) wants to execute other synchronized methods of the same object, it will be blocked until the thread(A) ends. But if threadB has access to different objects of the same class, none of them will be blocked.

The synchronized keyword penalizes the performance of the application, so you must only use it on methods that modify shared data in a concurrent environment.

If you have multiple threads calling a synchronized method, only one will execute them at a time while the others will be waiting. If the operation doesn't use the synchronized keyword, all the threads can execute the operation at the same time, reducing the total execution time.

If you know that a method will not be called by more than one thread, don't use the synchronized keyword.

We can use the synchronized keyword to protect the access to a block of code instead of an entire method. We should use the synchronized keyword in this way to protect the access to the shared data, leaving the rest of operations out of this block, obtaining a better performance of the application. The objective is to have the critical secion be as short as possible.

Normally, we will use the this keyword to reference the object that is executing the method.

synchronized (this) {
    // Java code
}

Arranging independent attributes in synchronized classes

When you use the synchronized keyword to protect a block of code, you must pass an object reference as a parameter. Normally, you will use the this keyword to reference the object that executes the method, but you can use other object references.

For example, if you have two independent attributes in a class shared by multiple threads, you must synchronize the access toe each variable, but there is no problem if there is one thread accessing one of the attributes and another thread accessing the other at the same time.

Using conditions in synchronized code

A classic problem in concurrent programming is the producer-consumer problem. We have a data buffer, one or more producers of data that save it in the buffer and one or more consumers of data that take it from the buffer.

As the buffer is a shared data structure, we have to control the access to it using a synchronization mechanism such as the synchronized keyword, but we have more limitations. A producer can't save data in the buffer if it's full and the consumer can't take data from the buffer if it's empty.

For these types of situations, Java provides the wait(), notify() and notifyAll() methods implemented in the Object class.

When the thread calls the wait() method, the JVM puts the thread to sleep and release the obejct that controls the synchronized block of code that it's executing and allows the other threads to execute other blocks of synchronized code protected by that object. To wake up the thread, you must call the notify() or notifyAll() method inside a block of code protected by the same object.

Synchronizing a block of code with a Lock

based on the Lock interface and classes that implement it (as ReentrantLock). This mechanism presents some advantages, which are as follows:

  • It allows the structuring of synchronized blocks in a more flexible way. With the synchronized keyword, you have to get and free the control over a synchronized block of code in a structured way. The Lock interfaces allow you to get more complex structures to implement your ciritical section.
  • The Lock interfaces provide additional functionalities over the synchronized keyword. One of the new functionalities is implemented by the tryLock() method. With the synchronized keyword, when a threadA tries to execute a synchronized block of code, if there is another threadB executing it, the threadA is suspended until the threadB finishes the execution of the synchronized block. With locks, you can execute the tryLock() method. This meothod returns a Boolean value indicating if there is another thread running the code protected by this lock.
  • The Lock interfaces allow a separation of read and write operations having multiple readers and only one modifier.
  • The Lock interfaces offer better performance than the synchronized keyword.

When we want to implement a critical section using locks and guarantee that only one execution thread runs a block of code, we have to create a ReentrantLock object.

At the beginning of the critical section, we have to get the control of the lock using the lock() method. When a threadA calls this method, if no other thread has the control of the lock, the method gives the threadA the control of the lock and returns immediately to permit the execution of the critical secion to this thread.

Otherwise, if there is another thread B executing the critical section controlled by this lock, the lock() method puts the thread A to sleep until the thread B finishes the execution of the critical section.

At the end of the critical section, we have to use the unlock() method to free the control of the lock and allow the other threads to run this critical section. If you don't call the unlock() method at the end of the critical section, the other threads that are waiting for that block will be waiting forever, causing a deadlock situation. If you use try-catch blocks in you critical section, don't forget to put the sentence containing the unlock() method inside the finally section.

The Lock interface includes another method to get the control of the lock. It's the tryLock() method. The biggest difference with the lock() method is that this method, if the thread that uses it can't get the control of the Lock interface, returns immediately and doesn't put the thread to sleep.

Synchronizing data access with read/write locks

ReentrantReadWriteLock has two locks, one for read operations and one for write operations. There can be more than one thread using read operations simultaneously, but only one thread can be using write operations. When a thread is doing a write operation, there can't be any thread doing read operations.

Modifying Lock fairness

The constructor of the ReentrantLock and ReentrantReadWriteLock classes admits a boolean parameter named fair that allows you to control the behavior of both classes.

The false value is the default value and it's called the non-fair mode. When there are some threads waiting for a lock and the lock has to select one of them to get the access to the critial section, it selects one without any criteria.

The true value is called the fair mode. When there are some threads waiting for a lock and the lock has to select one to get access to a critical section, it selects the thread that has been waiting for the most time.

As the tryLock() method doesn't put the thread to sleep if the Lock interface is used, the fair attribute doesn't affect its funcionality.

While Thread 0 is running the first block of code protected by the lock, we have nine threads waiting to execute that block of code. When Thread 0 releases the lock, immediately, it requests the lock again, so we have 10 threads trying to get the lock. As the fair mode is enabled, the Lock interface will choose Thread 1, so it's the thread that has been waiting for more time for the lock.

Using multiple conditions in a Lock

A lock may be associated with one or more conditions. The purpose of these conditions is to allow threads to have control of a lock and check whether a condition is true or not and, if it's false, be suspended until another thread wakes them up.

All the Condition objects are associated with a lock and created using the newCondition() method declared in the Lock interface. Before we can do any operation with a condition, you have to have the control of the lock associated with the condition, so the operations with conditions must by in a block of code that begins with a call to a lock() method of a Lock object and ends with an unlock() method of the same Lock object.

When a thread calls the await() method of a condition, it automatically frees the control of the lock, so that another thread can get it and begin the execution of the same, or another critical section protected by that lock.

When a thread calls the singal() or signalAll() methods of a condition, one or all of the theads that were waiting for that condition are woken up, but this doesn't guarantee that the condition that made them sleep is now true, so you must put the await() calls inside a while loop. You can't leave that loop until the condition is true. While the condition is false, you must call await() again.

2016/4/7 posted in  Java7 Concurrency Cookbook

Thread Management

Introduction

Inside a process, we can have various simultaneous tasks. The concurrent tasks that run inside a process are called threads.

We have two ways of creating a thread in Java:

  • Extending the Thread class and overriding the run() method
  • Building a class that implements the Runnable interface and then creating an object of the Thread class passing the Runnable object as a parameter

Calculator

public class Calculator implements Runnable
{
    private int number;

    public Calculator (int number)
    {
        this.number = number;
    }

    @Override
    public void run ()
    {
        for (int i = 1; i <= 10; i ++)
        {
            System.out.printf("%s: %d * %d = %d \n", Thread.currentThread().getName(), number, i, i * number);
        }
    }
}

Main

public class Main
{
    public static void main (String[] args)
    {
        for (int i = 1; i <= 10; i ++)
        {
            Calculator calculator = new Calculator(i);
            Thread thread = new Thread(calculator);
            thread.start();
        }
    }
}

Every Java program has at least on execution thread. When you run the program, the JVM runs this execution thread that calls the main() method of the program.

When you call the start() method of a Thread object, we are creating another execution thread.

A Java program ends when all its threads finish. If the initial thread ends, the rest of the threads will continue with their execution until they finish. If one of the threads use the System.exit() instruction to end the execution of the program, all the threads end their execution.

Creating an object of the Thread class doesn't create a new execution thread. Also, calling the run() method of a class that implements the Runnable interface doesn't create a new execution thread. Only calling the start() method creates a new execution thread.

Getting and setting thread information

The Thread class saves some information attributes that can help us to identify a thread. These attributes are:

  • ID: stores a unique identifier for each Thread
  • Name: stores the name of the Thread
  • Priority: stores the priority of the Thread object. Threads can have a priority between 1 and 10, where 1 is the lowest.
  • Status: stores the status of Thread. Thread can be in one of these six states: new, runnable, blocked, waiting, time waiting, or terminated.

The threads with the highest priority end before the ones with the lowest priority.

Interrupting a thread

A Java program with more than one execution thread only finishes when the execution of all of its threads end.

Java provides the interruption mechanism to indicate to a thread that we want to finish it. Thread has to check if it has been interrupted or not, and it can decide if it responds to the finalization request or not. Thread can ignore it adn continue with its execution.

The Thread class has an attribute that stores a boolean value indicating whether that thread has been interrupted or not. When you call the interrupt() method of a thread, you set that attribute to true. The isInterrupted() method only returns the value of that attribute.

You can throw InterruptedException when you detect the interruption of the thread and catch it in the run() method.

Sleeping and resuming a thread

Sometimes, the thread does nothing. During this time, the thread doesn't use any resources of the computer. After this time, the thread will be ready to continue with its execution when the JVM chooses it to be executed. You can use the sleep() method of the Thread class for this purpose.

Another possibility is to use the sleep() method of an element of the TimeUnit enumeration. This method uses the sleep() method of the Thread classes to put the current thread to sleep, but it receives the parameter in the unit that it represents and converts it to milliseconds.

When you call the sleep() method, Thread leaves the CPU and stops its execution for a period of time. During this time, it's not consuming CPU time, so the CPU can be executing other tasks.

When Thread is sleeping and is interrupted, the method throws an InterruptedException immediately and doesn't wait until the sleeping time finishes.

Waiting for the finalization of a thread

We may have a program that will begin initializing the resources it needs before proceeding with the rest of the execution. We can run the initializaion tasks as threads and wait for its finialization before continuing with the rest of the program.

For this purpose, we can use the join() method of the Thread class. When we call this method using a thread object, it suspends the execution of the calling thread until the object called finishes its execution.

Instead of waiting indefinitely for the finalization of the thread called, the calling thread waits for the milliseconds specified as a parameter of the method.

join(long milliseconds)

join(long milliseconds, long nanos)

For example, if the object thread1 has the code, thread2.join(1000), the thread thread1 suspends its execution until one of these two conditions is true:

  • thread2 finishes its execution
  • 1000 milliseconds have been passed

Creating and running a daemon thread

Deamon thread: has very low priority and normally only executes when no other thread of the same program is running. When daemon threads are the only threads running in a program, the JVM ends the program finishing thses thread.

They can't do important jobs because we don't know when they are going to have CPU time and they can finish any time if there aren't any other threads running. A typical example of these kind of threads is the Java garbage collector.

You only can call the setDaemon() method before you call the start() method. Once the thread is running, you can't modify its daemon status.

Processing uncontrolled exceptions in a thread

When a checked exception is thrown inside the run() method of a Thread object, we have to catch and treat them, because the run() method doesn't accept a throws clause.

When an unchecked exception is thrown inside the run() method of a Thread object, the default behavior is to write the stack trace in the console and exit the program.

When an exception is thrown in a thread and is not caught, the JVM checks if the thread has an uncaught execption handler set by the corresponding method. If it has, the JVM invokes this method with the Thread object and Exception as arguments.

If the thread has not got an uncaught exception handler, the JVM prints the statck trace in the console and exits the program.

Using local thread variables

If you create an object of a class that implements the Runnable interface and then start various Thread objects using the same Runnable object, all the threads share the same attributes. This meanns that, if you change an attribute in a thread, all the threads will be affected by this change.

Thread-local variables: sometimes, you will be interested in having an attribute that won't be shared between all the threads that run the same object.

private static ThreadLocal<Date> startDate = new ThreadLocal<Date>() {
   protected Date initialValue() {
       return new Date();
   }
};

Thread-local variables store a value of an attribute for each Thread that uses one of these variables. You can read the value using the get() method and changes the value using the set() method. The first time you access the value of a thread-local variable, if it has no value for the Thread object that it is calling, the thread-local variable calls the initialValue() method to assign a value for that Thread and returns the inital value.

The thread-local class provides the remove() method that deletes the value stored in the thread-local variable for the thread that it's calling.

If a thread A has a value in a thread-local variable and it creates another thread B, the thread B will have the same value as the thread A in the thread-local varaible. You can override the childValue() method that is called to initalize the value of the child thread in the thread-local variable.

Grouping threads into a group

threat the threads of a group as a single unit and provides access to the Thread objects that belong to a group to do an operation with them.

For example, you have some threads doing the same task and you want to control them, irrespective of how many threads are still running, the status of each one will interrupt all of them with a single call.

Java provides the ThreadGroup class to work with groups of threads. A ThreadGroup object can be formed by Thread objects and by another ThreadGroup object, generating a tree structure of threads.

Processing uncontrolled exceptions in a group of threads

Java implements an exception-based mechanism to manage error situations. Those exceptions are thrown by the Java classes when an error situation is detected.

Java also provides a mechanism to capture and process those exceptions. There are exceptions that must be captured or re-thrown using the throws clause of a method. These exceptions are called checked exceptions. Those not are unchecked exceptions.

When an uncaught exception is thrown in Thread, the JVM looks for three possible handlers for this exception.

  • it looks for the uncaught exception handler of the thread
  • If this handler doesn't exist, then the JVM looks for the uncaught exception handler for the ThreadGroup class of the thread
  • If this method doesn't exist, the JVM looks for the default uncaught exception handler

Creating threads through a factory

With this factory, we centralize the creation of objects with some advantages:

  • It's easy to change the class of the objects created or the way we create these objects
  • It's easy to limit the creation of objects for limited resources. For example, we can only have n objects of a type
  • It's easy to generate statistical data about the creation of the objets

Java provides an interface, the ThreadFactory interfaces to implement a Thread object factory.

The ThreadFactory interface has only one methods called newThread. Most basic ThreadFactory has only one line:

return new Thread(r);

You can improve this implementation by adding some variants by:

  • Creating personalized threads, using a special format for the name or even creating our own thread class that inherits the Java Thread class
  • Saving thread creation statistics
  • Limiting the number of threads created
  • Validating the creation of the threads
  • ...
2016/4/6 posted in  Java7 Concurrency Cookbook