Core Java

How to use Exchanger in Java with Example

Hello guys, if you are working in a concurrent Java application then you might have heard about the Exchanger class of java.util.concurrent package. The Exchanger in Java is another concurrency or synchronization utility introduced in Java 1.5 along with CountDownLatch, CyclicBarrier, and Semaphores. As the name suggests, the Exchanger allows two Threads to meet and exchange data at the rendezvous or meeting point. The 
java.util.Exchanger is a parametric class, which defines and holds the type of object to be exchanged. It has an overloaded method called the
exchange(), which is used to exchange objects between threads.

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 (see here) 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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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.
  
  * @author Javin Paul
  
  */
  
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()) {
1
2
3
4
5
6
7
8
  
                    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);
1
<br>
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 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(); 
1
<br>
1
2
//sleeping before starting consumer to give producer time to produce
        Thread.sleep(1000);
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 : []
1
<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.

That’s all on How to use Exchanger in Java. The exchanger class is a nice and simple synchronization utility and perfect for coordinating two threads. Exchanger should be used to implement a producer-consumer pattern with one producer and one consumer. If you like to learn more about Java concurrency classes I suggest you check out the following resources:

Further Learning

The Complete Java Masterclass

Java Multithreading, Concurrency, and Performance Optimization

Java Concurrency in Practice – The Book

Applying Concurrency and Multi-threading to Common Java Patterns

Other Java Concurrency Articles you may like

  • The 2020 Java Developer RoadMap (roadmap)
  • What is happens-before in Java Concurrency? (answer)
  • 10 Java Multithreading and Concurrency Best Practices (article)
  • Top 50 Multithreading and Concurrency Questions in Java (questions)
  • Top 5 Books to Master Concurrency in Java (books)
  • 10 Free Java Courses for Beginners and Intermediate developers (courses)
  • How to avoid deadlock in Java? (answer)
  • Understanding the flow of data and code in Java program (answer)
  • Is Java Concurrency in Practice still valid in 2020 (answer)
  • Difference between CyclicBarrier and CountDownLatch in Java? (answer)
  • 10 Tips to become a better Java Developer in 2020 (tips)
  • How to do inter-thread communication in Java using wait-notify? (answer)
  • Top 5 Courses to Learn Java Multithreading in-depth (courses)

Thanks for reading this article so far. If you like this Java Concurrency tutorial then please share it with your friends and colleagues. If you have any questions or feedback, then please drop a note.

P. S. – If you are new to Java world and want to learn core concepts along with Concurrency but looking for some free courses to start with then you can also check out this free Java Multithreading course on Udemy. It is a good free course to learn  Java Concurrency as well.

Published on Java Code Geeks with permission by Javin Paul, partner at our JCG program. See the original article here: How to use Exchanger in Java with Example

Opinions expressed by Java Code Geeks contributors are their own.

Javin Paul

I have been working in Java, FIX Tutorial and Tibco RV messaging technology from past 7 years. I am interested in writing and meeting people, reading and learning about new subjects.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button