Java Call Center example: threads synchronization with Semaphore and CyclicBarrier
To learn about Java threads and concurrency I have decided to represent a Call Center. The customers making the phone calls to a call center can be represented as threads.
To simulate the real world scenario I will use Semaphores and a Cyclic Barrier to simulate the standby situation.
It´s a simple Producer/Consumer scenario. The producers are the operators working in a call centers.
The critical block is the phone call, simulated with a thread sleep method.
First of all let´s start with semaphores.
Semaphores can control access to more than one resource at a time. They enable a certain amount of threads in a program block.
In the semaphore constructor you can specify the number of threads that can access the resource at the same time.
With the method acquire() the thread tries to get the resource. If the resource is busy, the thread will wait.
The release() method frees the resource from the thread.
CyclicBarrier offers an elegant way to trigger an event if all the operators are busy.
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.Semaphore; public class Customer extends Thread { CyclicBarrier standByMessage; private Semaphore operators; public Customer(Semaphore operators, CyclicBarrier standByMessage, String name) { this.standByMessage = standByMessage; this.operators = operators; this.setName(name); this.start(); } @Override public void run() { // simulate the time required for the phone call (between one and six seconds... long duration = ThreadLocalRandom.current().nextLong(1,10); try { System.out.println(getName() + " is waiting to speak to the operator..."); standByMessage.await(); // if you put acquire first and then await the operators are not // free and all the customers are not called operators.acquire(); System.out.println(getName() + " is getting the connection to the operator ..."); //using TimeUnit enumeration to make the code more readable Thread.sleep(TimeUnit.SECONDS.toMillis(duration)); System.out.println(getName() + "´s phone call with the operator ending."); operators.release(); System.out.println("Available operators=" + operators.availablePermits()); } catch (InterruptedException | BrokenBarrierException e) { System.err.println(e); } } }
Take a look at the way the duration of the call is generated. I am using the ThreadLocalRandom class, that in a multithreading context it´s helpful to get the job done much faster.
At first I tried it with Math.random() and it was MUCH slower!
The call center has 3 operators:
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.Semaphore; public class CallCenter { public static void main(String[] args) { Semaphore operators = new Semaphore(3); CyclicBarrier standbyMessage = new CyclicBarrier(3, new StandBy()); System.out.println("The call center is ready to answer phone calls"); System.out.println("Available operators initially=" + operators.availablePermits() ); new Customer(operators,standbyMessage,"Laura"); new Customer(operators,standbyMessage,"Mario"); new Customer(operators,standbyMessage,"Luigi"); new Customer(operators,standbyMessage,"Paola"); new Customer(operators,standbyMessage,"Alfonso"); new Customer(operators,standbyMessage,"Anna"); new Customer(operators,standbyMessage,"Giorgio"); new Customer(operators,standbyMessage,"Francesca"); new Customer(operators,standbyMessage,"Pietro"); new Customer(operators,standbyMessage,"Antonio"); new Customer(operators,standbyMessage,"Marco"); new Customer(operators,standbyMessage,"Giovanna"); new Customer(operators,standbyMessage,"Daniele"); new Customer(operators,standbyMessage,"Giorgio"); } }
The Cyclic barrier takes a Thread as argument for the constructor:
public class StandBy implements Runnable { @Override public void run() { System.out.println("All operators are busy at the moment - playing MUSIC ..."); } }
The output is something like:
The call center is ready to answer phone calls
Available operators initially=3
Alfonso is waiting to speak to the operator...
Laura is waiting to speak to the operator...
Paola is waiting to speak to the operator...
Luigi is waiting to speak to the operator...
Anna is waiting to speak to the operator...
Mario is waiting to speak to the operator...
Giorgio is waiting to speak to the operator...
All operators are busy at the moment - playing MUSIC ...
Francesca is waiting to speak to the operator...
Pietro is waiting to speak to the operator...
All operators are busy at the moment - playing MUSIC ...
Paola is getting the connection to the operator ...
Giovanna is waiting to speak to the operator...
Luigi is getting the connection to the operator ...
Marco is waiting to speak to the operator...
Antonio is waiting to speak to the operator...
Giorgio is waiting to speak to the operator...
All operators are busy at the moment - playing MUSIC ...
Daniele is waiting to speak to the operator...
Mario is getting the connection to the operator ...
All operators are busy at the moment - playing MUSIC ...
Luigi´s phone call with the operator ending.
Available operators=1
Alfonso is getting the connection to the operator ...
Mario´s phone call with the operator ending.
Available operators=1
Laura is getting the connection to the operator ...
Paola´s phone call with the operator ending.
Available operators=1
Francesca is getting the connection to the operator ...
Alfonso´s phone call with the operator ending.
Available operators=1
Pietro is getting the connection to the operator ...
Laura´s phone call with the operator ending.
Available operators=1
Marco is getting the connection to the operator ...
Francesca´s phone call with the operator ending.
Available operators=1
Anna is getting the connection to the operator ...
Pietro´s phone call with the operator ending.
Available operators=1
Giovanna is getting the connection to the operator ...
Anna´s phone call with the operator ending.
Available operators=1
Daniele is getting the connection to the operator ...
Marco´s phone call with the operator ending.
Available operators=1
Giorgio is getting the connection to the operator ...
Giorgio´s phone call with the operator ending.
Available operators=1
Giovanna´s phone call with the operator ending.
Available operators=2
Daniele´s phone call with the operator ending.
Available operators=3