This is a blocking method, which means the Thread, which calls the exchange() method wait at exchange point until another Thread arrives. Once another thread arrives, both exchange objects and return from this method. An overloaded version of the exchange method accepts additional TimeUnit object and wait until time out.
By the way, you can also interrupt a Thread waiting at the exchange point for other participants. Unlike CountDownLatch, CyclicBarrier, or Semaphore, the Exchanger utility can only synchronize two threads, which makes it ideal for solving the classical producer-consumer problem.
In this Java Concurrency tutorial, you will learn how to use Exchanger in Java by implementing a producer-consumer design pattern using Exchanger. Btw, I am assuming that you are familiar with Java programming syntax and semantics, if you are a complete beginner to Java then you may find it difficult to understand this example.
Java Exchanger Example
The Exchanger class is rather a simple synchronization utility to understand and use. In the last couple of concurrency tutorials, we have solved producer consumers using wait and notify and also implemented producer-consumer using BlockingQueue, now it’s time to use Exchanger to implement the same.
In this Java concurrency tutorial, we will be creating one producer and one consumer thread, which will exchange the buffer using the Exchanger utility class.
In general, here is how Exchanger works :
1. You first create an Exchange object like Exchanger<Deque<Long>> stringExchanger = new Exchanger<>(); this defines what type of object will be exchanged between threads. In this case, two threads will exchange the Deque object, containing long values.
2. When Thread A is ready to exchange its buffer or object, it calls the
Exchanger.exchange() method. This is a blocking method, and Thread A will be blocked until Thread B come and transfer its objects to Thread A or Thread A is interrupted or timeout.
3. When Thread B is ready, it also calls the exchange() method. Now both Thread A and B exchange each other’s object and return from the exchange method.
4. Once the exchange completes, Thread A has Thread B’s object and vice-versa.
On the same note, I would like to emphasize the importance of Java concurrency skills and urge every Java developer to spend some time mastering Java concurrent classes.
Java Program with Exchanger in Concurrency
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.Exchanger;
/**
* Exchanger Example in Java. Exchanger allows two Threads to meet at exchange
* point and exchange data structure or objects. In this Java program, exchanger
* is used to exchange buffer between producer and consumer.
*/
public class JavaExchangerTutorail {
public static void main(String args[]) throws InterruptedException {
//Creating Exchanger to exchange String object with other thread
final Exchanger> exchanger = new Exchanger>();
Thread producer = new Thread("Producer : "){
@Override
public void run(){
Deque stack = new ArrayDeque();
//producer thread insert elments into stack
while (stack.isEmpty()) {
stack.add(System.nanoTime()%1000);
//if stack is not empty then exchange it to consumer thread
try {
System.out.println(Thread.currentThread().getName()
+ " ready to exchange : " + stack);
<br>
// Exchanger return other Thread's object
stack = exchanger.exchange(stack);
System.out.println(Thread.currentThread().getName()
+ " got : " + stack);
} catch (InterruptedException ie) { ie.printStackTrace(); }
}
}
};
Thread consumer = new Thread("Consumer : "){
@Override
public void run(){
Deque stack = new ArrayDeque();
//consumer thread takes object from stack and prints
do{
//if stack is empty then exchange it to producer for refill
try {
System.out.println(Thread.currentThread().getName()
+ " ready to exchange : " + stack);
stack = exchanger.exchange(stack);
System.out.println(Thread.currentThread().getName()
+ " got : " + stack);
stack.remove();
} catch (InterruptedException ie) { ie.printStackTrace(); }
}while(stack.isEmpty()) ;
}
};
producer.start();
<br>
//sleeping before starting consumer to give producer time to produce
Thread.sleep(1000);
consumer.start();
}
}
Output:
Producer : ready to exchange : [247]
Consumer : ready to exchange : []
Producer : got : []
Consumer : got : [247]
Producer : ready to exchange : [692]
Consumer : ready to exchange : []
Consumer : got : [692]
Consumer : ready to exchange : []
Producer : got : []
<br>
Explanation of Code and Output
If you look at the above example, all code is inside the main method. We have made the Exchanger instance final because we are accessing them from Anonymous inner class, and only final local variables are accessible from the anonymous inner class.
Later, we created two threads, Producer and Consumer. The producer checks the queue and if it’s empty, it adds the last three digits of current nano time and calls the exchange() method.
Now, until the Consumer thread arrives at the exchange point, I mean until it calls the exchange() method, the Producer thread will be blocked.
Once a consumer arrives, both exchange each other’s stack and return from the exchange() method. At this time, the Producer has an empty stack of consumers and the consumer has a non-empty stack of Producer, I mean, they have each other’s object.
For understanding, which thread is exchanging which stack, we print the content of stack before and after an exchange on each thread. If you look at the output, it’s self-explanatory.
By the way, as with threads, you are not guaranteed to get the output in the same order. In the third iteration, you can see the consumer has an emptied stack and ready to exchange empty stack even before producer thread gets scheduled and return from the exchange method.
Source: javacodegeeks.com
0 comments:
Post a Comment