In this example I show an usage of two more concurrent classes CyclicBarrier
and Semaphore
; which are both provided in the core Java library. There's a wealth of concurrency classes built directly into the JVM that can really simplify multi-threaded development.
In the example below, I use a cyclic barrier to make several threads wait for alignment. This is a common example where we have many threads and need to wait for all threads to reach a barrier before proceeding:
package com.thecoderscorner.example;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* This class shows the usage of the CyclicBarrier class in the form
* of a simple three thread example. We wait for all threads to
* reach the cyclic barrier and then the threads print a log line
* and exit.
*/
public class CyclicBarrierExample {
// create a cyclic barrier that will wait for three calls before
// unlocking
private static final int NO_OF_THREADS = 3;
private CyclicBarrier barrier = new CyclicBarrier(NO_OF_THREADS);
public static void main(String[] args) throws InterruptedException {
CyclicBarrierExample instance = new CyclicBarrierExample();
instance.init();
}
public void init() throws InterruptedException {
// create three threads that will call await on the cyclic barrier
for (int i=0; i<NO_OF_THREADS; ++i) {
Thread th = new Thread(new MyWorkerThread(), "Worker" + i);
th.start();
// to help visualise I add a delay between creation
Thread.sleep(1000);
}
}
/**
* Here is the runnable used by the above threads, it just waits for the
* barrier before proceeding to log a line and exit. Notice that the
* barrier unlocked log line only occurs after all three threads reach
* the barrier.
*/
private class MyWorkerThread implements Runnable {
@Override
public void run() {
System.out.println("Thread started");
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("Barrier unlocked");
}
}
}
And the output of the above is below, notice that all threads wait at the barrier until the last one reaches there, and then they all proceed.
Thread started Thread started Thread started Barrier unlocked Barrier unlocked Barrier unlockedProcess finished with exit code 0
In this example we use a semaphore to limit the number of threads that can proceed through a section of code, in this case we use a good old sleep to simulate a long lived operation:
package com.thecoderscorner.example;
import java.util.concurrent.Semaphore;
/**
* This example shows an example usage of a semaphore where three threads
* are trying to gain access to a semaphore that only has two places. For
* the sake of this example each thread takes a place and waits one second
* before releasing the place. We will see there is only ever two threads
* that are within the block between acquire and release.
*/
public class SemaphoreExample {
private static final int DEFAULT_PERMITS = 2;
private static final int NO_OF_THREADS = 3;
private Semaphore semaphore = new Semaphore(DEFAULT_PERMITS);
private void init() {
for(int i=0; i<NO_OF_THREADS; ++i) {
Thread th = new Thread(new SemaphoreTestThread());
th.start();
}
}
/**
* Each thread will look a few times and attempt to take the semaphore.
* What we will see is that there will never be more than two threads
* in the sleep section at once.
*/
private class SemaphoreTestThread implements Runnable {
@Override
public void run() {
try {
for(int i=0;i<NO_OF_THREADS;i++) {
semaphore.acquire();
System.out.println("Semaphore acquired");
// only ever two threads here
Thread.sleep(1000);
semaphore.release();
System.out.println("Semaphore released");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SemaphoreExample example = new SemaphoreExample();
example.init();
}
}
And the output of the above, notice that there are only ever two threads in the semaphore
Semaphore acquired Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore acquired Semaphore released Semaphore released Semaphore acquired Semaphore releasedProcess finished with exit code 0