java.util.concurrent包(7)——Exchanger使用

Java 併發 API 提供了一種允許2個併發任務間相互交換數據的同步應用。更具體的說,Exchanger類允許在2個線程間定義同步點,當2個線程到達這個點,他們相互交換數據類型,使用第一個線程的數據類型變成第二個的,然後第二個線程的數據類型變成第一個的。

示例1
一個人有零食,另一個人有錢,他們兩個想等價交換,對好口號在某個地方相見,一個人先到了之後,必須等另一個人帶着需要的東西來了之後,才能開始交換。
public class ExchangerTest
{
public static void main(String[] args)
{
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> exchanger = new Exchanger<String>();
service.execute(new Runnable()
{
public void run()
{
try
{
String data1 = "零食";
System.out.println("線程" + Thread.currentThread().getName() + "正在把數據" + data1 + "換出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = exchanger.exchange(data1);
System.out.println("線程" + Thread.currentThread().getName() + "換回的數據爲" + data2);
}
catch (Exception e)
{
}
}
});

service.execute(new Runnable()
{
public void run()
{
try
{
String data1 = "錢";
System.out.println("線程" + Thread.currentThread().getName() + "正在把數據" + data1 + "換出去");
Thread.sleep((long) (Math.random() * 1000));
String data2 = exchanger.exchange(data1);
System.out.println("線程" + Thread.currentThread().getName() + "換回的數據爲" + data2);
}
catch (Exception e)
{
}
}
});
}
}
線程pool-1-thread-1正在把數據零食換出去
線程pool-1-thread-2正在把數據錢換出去
線程pool-1-thread-2換回的數據爲零食
線程pool-1-thread-1換回的數據爲錢


示例2
這個類在遇到類似生產者和消費者問題時,是非常有用的。來一個非常經典的併發問題:你有相同的數據buffer,一個或多個數據生產者,和一個或多個數據消費者。只是Exchange類只能同步2個線程,所以你只能在你的生產者和消費者問題中只有一個生產者和一個消費者時使用這個類。
public class Producer implements Runnable
{

// 要被相互交換的數據類型。
private List<String> buffer;

// 用來同步 producer和consumer
private final Exchanger<List<String>> exchanger;

public Producer(List<String> buffer, Exchanger<List<String>> exchanger)
{
this.buffer = buffer;
this.exchanger = exchanger;
}

public void run()
{
// 實現10次交換
for (int i = 0; i < 10; i++)
{
buffer.add("第" + i + "次生產者的數據" + i);
try
{
// 調用exchange方法來與consumer交換數據
System.out.println("第" + i + "次生產者在等待.....");
buffer = exchanger.exchange(buffer);
System.out.println("第" + i + "次生產者交換後的數據:" + buffer.get(i));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}


public class Consumer implements Runnable
{

// 用來相互交換
private List<String> buffer;

// 用來同步 producer和consumer
private final Exchanger<List<String>> exchanger;

public Consumer(List<String> buffer, Exchanger<List<String>> exchanger)
{
this.buffer = buffer;
this.exchanger = exchanger;
}

public void run()
{
// 實現10次交換
for (int i = 0; i < 10; i++)
{
buffer.add("第" + i + "次消費者的數據" + i);
try
{
// 調用exchange方法來與consumer交換數據
System.out.println("第" + i + "次消費者在等待.....");
buffer = exchanger.exchange(buffer);
System.out.println("第" + i + "次消費者交換後的數據:" + buffer.get(i));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}

public class Core
{
public static void main(String[] args)
{
// 創建2個buffers,分別給producer和consumer使用
List<String> buffer1 = new ArrayList<String>();
List<String> buffer2 = new ArrayList<String>();

// 創建Exchanger對象,用來同步producer和consumer
Exchanger<List<String>> exchanger = new Exchanger<List<String>>();

// 創建Producer對象和Consumer對象
Producer producer = new Producer(buffer1, exchanger);
Consumer consumer = new Consumer(buffer2, exchanger);

// 創建線程來執行producer和consumer並開始線程
Thread threadProducer = new Thread(producer);
Thread threadConsumer = new Thread(consumer);
threadProducer.start();
threadConsumer.start();
}
}
Exchanger 類有另外一個版本的exchange方法
exchange(V data, long time, TimeUnit unit)
V是聲明參數種類,例子中是List
此線程會休眠直到另一個線程到達並中斷它,或者特定的時間過去了
TimeUnit類有多種常量,DAYS、HOURS、MICROSECONDS、MILLISECONDS、MINUTES、NANOSECONDS和SECONDS

原帖地址:
http://blog.csdn.net/howlaa/article/details/19853447
http://ifeve.com/thread-synchronization-utilities-8/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章