(No nonsense, only dry goods) Detailed explanation of Exchanger tool to solve the problem of collaboration between threads

A long time ago I wrote an article on how to communicate between threads. At that time, I used the wait notification model. This article introduced a Java tool class Exchanger for communication between two threads.

1. Concept understanding

The role of Exchanger is to exchange data between two threads. It provides an internal method exchange. This internal method is like a synchronization point. Only when both methods reach the synchronization point can data be exchanged. Let's change a picture to demonstrate a wave.

image

That is to say, only thread A and thread B reach the synchronization point before they can exchange data.

Let's go directly to the code to see how to use it, and then see what we need to pay attention to when using it.

Two, use cases

1. Basic use

First we define a test class ExchangerTest:

1public class ExchangerTest {
2    private static Exchanger<String> exchanger = new Exchanger<>();
3    private static String threadA_data = "100块";
4    private static String threadB_data = "50块";
5    public static void main(String[] args) {
6        new ThreadA(exchanger, threadA_data).start();
7        new ThreadB(exchanger, threadB_data).start();
8    }
9}

In this class, we use two threads ThreadA and ThreadB to exchange data, and then we define an exchange Exchanger to exchange. Let's take a look at how these two threads are implemented.

 1public class ThreadA extends Thread {
2    private Exchanger<String> exchanger = new Exchanger<>();
3    private String data = null;
4    public ThreadA(Exchanger<String> exchanger, String data) {
5        this.exchanger = exchanger;
6        this.data = data;
7    }
8    @Override
9    public void run() {
10        try {
11            TimeUnit.SECONDS.sleep(3);
12            System.out.println("线程A交换前的数据是:"+data);
13            data = exchanger.exchange(data);
14            System.out.println("线程A交换后的数据是:"+data);
15        } catch (InterruptedException e) {
16            e.printStackTrace();
17        }
18    }
19}

Here we mainly look at the implementation of the run method. First, we print out the data information before the exchange, then use the switch to exchange the data, and finally print out the data after the exchange. Since ThreadB and ThreadA are implemented in the same way, here we only give a piece of code. Below we can run it to see the test results:

Now we see that thread A and thread B can exchange normally. Through this case, we will find that Exchanger is really super simple to use. But it looks very simple. In fact, many pits have been dug. Let's take a look.

Note one: the two threads must eventually reach the synchronization point

What does it mean? Let's draw a picture and give an example.

image

The above picture means this way. The thread on the left has 20 seconds to reach the synchronization point, but the thread on the right has a timeout. If the other party does not arrive after 10 seconds, the transaction will fail. There are also exceptions to our program. Let's demonstrate the code:

First, this time we look at the thread A on the right: the timeout period is set to 10 seconds

 1public class ThreadA extends Thread {
2    private Exchanger<String> exchanger = new Exchanger<>();
3    private String data = null;
4    public ThreadA(Exchanger<String> exchanger, String data) {
5        this.exchanger = exchanger;
6        this.data = data;
7    }
8    @Override
9    public void run() {
10        try {
11            TimeUnit.SECONDS.sleep(3);
12            System.out.println("线程A交换前的数据是:"+data);
13            //线程A:设置超时时间为10秒,对应于右边的线程
14            data = exchanger.exchange(data,10,TimeUnit.SECONDS);
15            System.out.println("线程A交换后的数据是:"+data);
16        } catch (InterruptedException | TimeoutException e) {
17            e.printStackTrace();
18        }
19    }
20}

Then there is thread B on the left: it will take 20 seconds to arrive

 1public class ThreadB extends Thread {
2    private Exchanger<String> exchanger = new Exchanger<>();
3    private String data = null;
4    public ThreadB(Exchanger<String> exchanger, String data) {
5        this.exchanger = exchanger;
6        this.data = data;
7    }
8    @Override
9    public void run() {
10        try {
11            //我还有20秒才可以抵达
12            TimeUnit.SECONDS.sleep(20);
13            System.out.println("线程B交换后的数据hashcode是:"+data.hashCode());
14            data = exchanger.exchange(data);
15            System.out.println("线程B交换后的数据hashcode是:"+data.hashCode());
16        } catch (InterruptedException e) {
17            e.printStackTrace();
18        }
19    }
20}

Now let's test it again and see what results will appear:

image

We find that thread A has waited for 10 seconds, but thread B has not arrived, so the transaction is declared as failed. The program has a timeout exception.

Note 2: The exchanged threads must appear in pairs

What does this note mean? In fact, it just can't be single, it's like looking for a partner. In the end, it is always in pairs. If there are 5 males and 4 females, what about the remaining male compatriots, I can only wait there. We can also test this code, but a new thread C is added. The test code changes:

 1public class ExchangerTest3 {
2    private static Exchanger<String> exchanger = new Exchanger<>();
3    private static String threadA_data = "100块";
4    private static String threadB_data = "50块";
5    private static String threadC_data = "10块";
6    public static void main(String[] args) {
7        new ThreadA(exchanger, threadA_data).start();
8        new ThreadB(exchanger, threadB_data).start();
9        new ThreadC(exchanger, threadC_data).start();
10    }
11}

At this point, when we go to the test, we will find that there is always a thread waiting in an endless loop.

image

Note three: multiple threads exchange data

We mentioned above that after the exchanged threads are paired, no single can be placed. If there are multiple pairs of threads at this time, who will pair with whom? Let's tell you the answer first, that is random matching.

Here we continue to add a thread D on the basis of note two, and then continue to change our test class to run:

image

For the use of Exchanger, basically you need to pay attention to so much. Hope it helps you.


Guess you like

Origin blog.51cto.com/15082402/2592674