Exchanger class is introduced with java 1.5 with other classes such ConcurrentHashMap, CountDownLatch, Semaphores.
Exchanger class is used to exchange object between two threads. Exchanger simply waits until two separate threads calls exchange method, when it happens, it exchanges data supplied by threads.Two threads can pair and swap objects between them. Exchanger class may be useful in genetic algorithms or pipeline design.
It has two overloaded version of exchange method.
- exchange(V x): It waits for another thread to arrive at exchange point and exchange object with that thread.
- exchange(V x, long timeout, TimeUnit unit): It waits for another thread for specific time interval provided in the method and exchange object with that thread.
Let’s understand with help of example:
We have two threads i.e. Producer and Consumer and they will exchange Country objects. Producer will create Country objects and Consumer will return dummy country objects.
Let’s first create Country class. It just have one attribute called countryName.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package org.arpit.java2blog;
public class Country {
private String countryName;
public Country(String countryName) {
super();
this.countryName = countryName;
}
public String getCountryName() {
return countryName;
}
}
|
Now we will create main class called ExchangerExampleMain.java and it will have two other classes called Producer and Consumer which will implement runnable interface.
1
2
3
4
5
6
7
8
9
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package org.arpit.java2blog;
import java.util.concurrent.Exchanger;
public class ExchangerExampleMain {
public static void main(String[] args) {
Exchanger exchanger = new Exchanger();
// Starting two threads
new Thread(new Producer(exchanger)).start();
new Thread(new Consumer(exchanger)).start();
}
}
class Producer implements Runnable {
Exchanger ex;
Producer(Exchanger ex){
this.ex = ex;
}
@Override
public void run() {
for(int i = 0; i < 2; i ++){
Country country=null ;
if(i==0)
country =new Country("India");
else
country =new Country("Bhutan");
try {
// exchanging with an dummy Country object
Country dummyCountry = ex.exchange(country);
System.out.println("Got country object from Consumer thread : "+dummyCountry.getCountryName());
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
class Consumer implements Runnable {
Exchanger ex;
Consumer(Exchanger ex){
this.ex = ex;
}
@Override
public void run() {
for(int i = 0; i < 2; i ++){
try {
// Getting Country object from producer thread
// giving dummy country object in return
Country country = ex.exchange(new Country("Dummy"));
System.out.println("Got country object from Producer thread : "+country.getCountryName());
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
|
When you run above program, you will get below output.
|
Got country object from Consumer thread : Dummy
Got country object from Producer thread : India
Got country object from Consumer thread : Dummy
Got country object from Producer thread : Bhutan
|
If you notice, producer has exchanged two country object (India and Bhutan) with consumer and got dummy country objects in return.
If you want to understand more realistic use of Exchanger. Producer and consumer may exchange buffers. When buffer is full, Producer will provide full buffer to consumer and Consumer will return empty buffer in return.