Wednesday, November 11, 2020

How to use Exchanger for sharing Object between Threads in Java [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. This means you can use Exchanger to share objects between threads and for inter-thread communication. 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 the 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 an 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.

In that case, I suggest you first go through a comprehensive Java course like The Complete Java Masterclass by Tim Buchalaka on Udemy.  It's is also very affordable and you can buy in just $10 on Udemy sales which happen every now and then.





Java Exchanger Example for Inter thread communication

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 comes 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. If you agree with me and need a resource to level up your Java Concurrency skills then I highly recommend you go through the classic Java Concurrency in Practice book and Multithreading and Parallel Computing in Java course on Udemy, both are awesome resources.





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.
 
  * @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&gt; exchanger = new Exchanger&gt;();
  
        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);

                        // 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(); 
        
        //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 : []


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 the 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 the 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 the empty stack even before the 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)
  • How Happens Before works 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 the 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.

No comments :

Post a Comment