Exchanger的工作原理及例項
1.實現原理
Exchanger(交換者)是一個用於執行緒間協作的工具類。Exchanger用於進行執行緒間的資料交換。它提供一個同步點,在這個同步點兩個執行緒可以交換彼此的資料。這兩個執行緒通過exchange方法交換資料, 如果第一個執行緒先執行exchange方法,它會一直等待第二個執行緒也執行exchange,當兩個執行緒都到達同步點時,這兩個執行緒就可以交換資料,將本執行緒生產出來的資料傳遞給對方。因此使用Exchanger的重點是成對的執行緒使用exchange()方法,當有一對執行緒達到了同步點,就會進行交換資料。因此該工具類的執行緒物件是成對的。
Exchanger類提供了兩個方法,String exchange(V x):用於交換,啟動交換並等待另一個執行緒呼叫exchange;String exchange(V x,long timeout,TimeUnit unit):用於交換,啟動交換並等待另一個執行緒呼叫exchange,並且設定最大等待時間,當等待時間超過timeout便停止等待。
2.例項講解
通過以上的原理,可以知道使用Exchanger類的核心便是exchange()方法的使用,接下來通過一個例子來使的該工具類的用途更加清晰。該例子主要講解的是前段時間NBA交易截止日的交易。
package concurrent;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.*;
public class ExchangerDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
executor.execute(new Runnable() {
String data1 = "克拉克森,小拉里南斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "格里芬";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "哈里斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "以賽亞托馬斯,弗萊";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.shutdown();
}
private static void nbaTrade(String data1, Exchanger exchanger) {
try {
System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = (String) exchanger.exchange(data1);
System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
執行程式,得到如下結果:
pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
pool-1-thread-2在交易截止之前把 格里芬 交易出去
pool-1-thread-3在交易截止之前把 哈里斯 交易出去
pool-1-thread-4在交易截止之前把 以賽亞托馬斯,弗萊 交易出去
pool-1-thread-2交易得到哈里斯
pool-1-thread-3交易得到格里芬
pool-1-thread-4交易得到克拉克森,小拉里南斯
pool-1-thread-1交易得到以賽亞托馬斯,弗萊
以上例子可以看出兩個都呼叫exchange()方法的執行緒會進行交換資料。接下來假設執行緒數目只有奇數個,觀察情況:
如以下程式碼,將第四個執行緒註釋掉。
package concurrent;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.*;
public class ExchangerDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
executor.execute(new Runnable() {
String data1 = "克拉克森,小拉里南斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "格里芬";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
executor.execute(new Runnable() {
String data1 = "哈里斯";
@Override
public void run() {
nbaTrade(data1, exchanger);
}
});
// executor.execute(new Runnable() {
// String data1 = "以賽亞托馬斯,弗萊";
//
// @Override
// public void run() {
// nbaTrade(data1, exchanger);
// }
// });
executor.shutdown();
}
private static void nbaTrade(String data1, Exchanger exchanger) {
try {
System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = (String) exchanger.exchange(data1);
System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
執行程式,得到如下結果:
pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
pool-1-thread-2在交易截止之前把 格里芬 交易出去
pool-1-thread-3在交易截止之前把 哈里斯 交易出去
pool-1-thread-3交易得到格里芬
pool-1-thread-2交易得到哈里斯
由結果可知,執行緒2和執行緒3進行了交換資料,而執行緒1一直等待與它交換資料的執行緒呼叫exchange,但是隻有3個執行緒,所以會一直等待。
因此,當兩個執行緒之間出現資料交換的情況,可以使用Exchanger工具類實現資料交換。注意exchange方法的含義,以及觸發資料交換的條件。
相關文章
- NIO原理及例項
- SpringCloud——Feign例項及原理SpringGCCloud
- pr劫持的原理及操作例項、pr劫持的原理
- 一圖看懂區塊鏈的工作原理、技術及用例區塊鏈
- 詳解 AWS 的突發效能例項:CPU 和頻寬突發的工作原理
- Python物件導向多型實現原理及程式碼例項Python物件多型
- 伺服器重置例項後的部署工作伺服器
- YUM工作原理及使用
- JSTL的標籤及使用,包含例項JS
- Python中的if、while、for 語法及例項PythonWhile
- TRIZ 機械振動原理 例項
- ActiveMQ的使用及整合spring的使用例項MQSpring
- Vue例項及生命週期Vue
- ppium簡介及工作原理
- 大神教你C++寫時複製實現原理及例項解析C++
- JavaScript中常用的事件程式碼及例項JavaScript事件
- Spring WebFlux 的設計及工作原理剖析SpringWebUX
- 封裝動態庫dll與靜態庫lib(原理及簡單例項)封裝單例
- WebSocket 簡介及應用例項Web
- redis應用場景及例項Redis
- EventBus詳解及簡單例項單例
- springmvc工作原理及原始碼分析SpringMVC原始碼
- Thanos工作原理及元件簡介元件
- php例項化物件的例項方法PHP物件
- Python中compile函式的語法及例項!PythonCompile函式
- SSL解除安裝的工作原理及好處
- Spring 原始碼分析之 bean 例項化原理Spring原始碼Bean
- EntityFramework Core上下文例項池原理分析Framework
- guava之ImmutableMap使用例項及好處Guava
- 【JMicro】微服務部署架構及例項微服務架構
- Openlayer add mark及新增hover效果例項
- Verilog設計技巧例項及實現
- Cookie、localStorage 和 sessionStorage 的區別及應用例項CookieSession
- 實現繼承的幾種方式及工作原理繼承
- IIC序列匯流排的組成及工作原理
- 海外IP池的工作原理及應用場景
- PostgreSQL的AutoVacuum原理及autovacuum不工作問題解析SQL
- 電感器的工作原理及主要型別gujing型別