(不談廢話,只有乾貨)解決線程間協做問題的工具類Exchanger詳解

在好久以前我曾寫過一篇一篇文章介紹線程間如何進行通訊的問題,當時使用的是等待通知模型,這篇文章介紹一個java提供的用於兩個線程間通訊的工具類Exchanger。java

1、概念理解

Exchanger的做用就是爲了兩個線程之間交換數據,他提供了一個內部方法exchange,這個內部方法就比如是一個同步點,只有兩個方法都到達同步點,才能夠交換數據。咱們換一張圖來演示一波。ide

圖片

也就是說只有線程A和線程B都到達同步點,才能夠交換數據。工具

咱們上代碼直接看看如何使用,而後再去看看使用的時候須要注意什麼。測試

2、使用案例

一、基本使用this

首先咱們定義一個測試類ExchangerTest:spa

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}

在這個類中,咱們使用了ThreadA和ThreadB兩個線程交換數據,而後咱們定義了一個交換器Exchanger來交換。下面咱們看看這倆線程是如何實現的。線程

 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}

在這裏咱們主要是看run方法的實現,首先咱們打印出交換以前的數據信息,而後使用交換器交換數據,最後再打印出交換以後的數據。因爲ThreadB和ThreadA實現方式同樣,在這裏咱們只給出一份代碼便可。下面咱們就能夠運行一下,看看測試結果:code

如今咱們看到,線程A和線程B就能夠正常的進行交換了。經過這個案例咱們會發現,Exchanger使用起來真的是超級簡單。不過看起來很簡單,其實還挖了不少的坑,下面咱們來看看。orm

注意點一:兩個線程最終必須到達同步點

這是什麼意思呢?咱們畫一張圖,舉一個例子。對象

圖片

上面這張圖的意思是這個樣子的,左邊的線程還有20秒才能夠到達同步點,可是右邊的線程設置了超時時間,若是10秒鐘後對方沒有到達,那麼此次交易就宣告失敗。對於咱們的程序來講也會出現異常。咱們代碼演示一下:

首先此次咱們看右邊的線程A:設置了超時時間爲10秒

 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}

而後就是左邊的線程B:還須要20秒才能夠抵達

 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}

如今咱們再去測試一下看看會出現什麼結果:

圖片

咱們發現線程A等待了10秒以後,線程B尚未到達,那就宣告交易失敗。程序出現超時異常。

注意點二:交換的線程必須成對出現

這個注意點是什麼意思呢?其實就是不能是單,就比如是找對象,最後老是成雙成對的,要是5個男的4個女的,那剩下的一個男同胞怎麼辦,只能在那傻等了。這個咱們也能夠代碼測試一下,只是新增了一個線程C。測試代碼變一下:

 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}

此時咱們再去測試,就會發現,總有一個線程處於死循環一直等待的狀態。

圖片

注意點三:多個線程交換數據

上面咱們提到了交換的線程配對以後不能落單,那麼若是此時有多個成對的線程了,誰和誰配對呢?答案咱們先告訴你,那就是胡亂配對。

在這裏咱們在注意點二的基礎之上繼續增長一個線程D,而後繼續更改咱們的測試類運行一下:

圖片

對於Exchanger的使用基本上須要注意的就是這麼多。但願對你有幫助。

相關文章
相關標籤/搜索