创建Data 角色的线程(Producer)和使用Data的角色的线程(Consumer)正在运行,假设现在我们想要从Producer角色向Consumer 角色传递Data角色。
这时我们需要在Producer角色和Consumer角色之间设置一个Channel角色,用于存储想要传递的Data角色。Channel角色担当着Data角色的中转地、桥梁、通道任务。
由于将有多个线程使用Channel角色,所以我们需要在Channel角色中执行互斥处理。在Channel角色中。
这样,线程之间便可以安全地进行通信。如果Channel角色可存储的Data角色数量足够多,那么便可以缓解Producer角色和Consumer角色之间处理速度的差异。
代码样例:
Producer 生产者
package pattern.ProducerConsumer;
import java.util.Random;
/**
* 生产者
*/
public class MakerThread extends Thread {
private final Random random;
private final Table table;
private static int id = 0; // 蛋糕的流水号(所有糕点师共用)
public MakerThread(String name, Table table, long seed) {
super(name);
this.table = table;
this.random = new Random(seed);
}
public void run() {
try {
while (true) {
Thread.sleep(random.nextInt(1000));
String cake = "[ Cake No." + nextId() + " by " + getName() + " ]";
table.put(cake);
}
} catch (InterruptedException e) {
}
}
private static synchronized int nextId() {
return id++;
}
}
Consumer 消费者
package pattern.ProducerConsumer;
import java.util.Random;
/**
* 消费者
*/
public class EaterThread extends Thread {
private final Random random;
private final Table table;
public EaterThread(String name, Table table, long seed) {
super(name);
this.table = table;
this.random = new Random(seed);
}
public void run() {
try {
while (true) {
String cake = table.take();
Thread.sleep(random.nextInt(1000));
}
} catch (InterruptedException e) {
}
}
}
Channel
package pattern.ProducerConsumer;
/**
* channel
*/
public class Table {
private final String[] buffer;
private int tail; // 下次put的位置
private int head; // 下次take的位置
private int count; // buffer中的蛋糕个数
public Table(int count) {
this.buffer = new String[count];
this.head = 0;
this.tail = 0;
this.count = 0;
}
// 放置蛋糕
public synchronized void put(String cake) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " puts " + cake);
while (count >= buffer.length) {
wait();
}
buffer[tail] = cake;
tail = (tail + 1) % buffer.length;
count++;
notifyAll();
}
// 取蛋糕
public synchronized String take() throws InterruptedException {
while (count <= 0) {
wait();
}
String cake = buffer[head];
head = (head + 1) % buffer.length;
count--;
notifyAll();
System.out.println(Thread.currentThread().getName() + " takes " + cake);
return cake;
}
}
Main 线程启动主类
package pattern.ProducerConsumer;
public class Main {
public static void main(String[] args) {
Table table = new Table(3); // 创建一个能放置3个蛋糕的桌子
new MakerThread("MakerThread-1", table, 31415).start();
new MakerThread("MakerThread-2", table, 92653).start();
new MakerThread("MakerThread-3", table, 58979).start();
new EaterThread("EaterThread-1", table, 32384).start();
new EaterThread("EaterThread-2", table, 62643).start();
new EaterThread("EaterThread-3", table, 38327).start();
}
}
使用java.util.concurrent.Exchanger 类交换缓冲区
向缓冲区中填充字符的ProducerThread 类和从缓冲区中取出取出字符的ConsumerThread类之间互相交换缓冲区。
Main类 将buffer1缓冲区传给ProducerThread,然后将buffer2缓冲区传给ConsumerThread,同时还会将通用的Exchanger的实例分别传给ProducerThread和ConsumerThread
ProducerThread
-
填充字符,直至缓冲区被填满
-
使用exchange方法将填满的缓冲区传递给ConsumerThread
-
传递缓冲区后,作为交换,接收空的缓冲区
ConsumerThread
-
使用exchange方法将空的缓冲区传递给ProducerThread
-
传递空的缓冲区后,作为交换,接收被填满字符的缓冲区
-
使用缓冲区中的字符
Main
package pattern.ProducerConsumer.exchanger;
import java.util.concurrent.Exchanger;
public class Main {
public static void main(String[] args) {
Exchanger<char[]> exchanger = new Exchanger<char[]>();
char[] buffer1 = new char[10];
char[] buffer2 = new char[10];
new ProducerThread(exchanger, buffer1, 314159).start();
new ConsumerThread(exchanger, buffer2, 265358).start();
}
}
ProducerThread
package pattern.ProducerConsumer.exchanger;
import java.util.Random;
import java.util.concurrent.Exchanger;
public class ProducerThread extends Thread {
private final Exchanger<char[]> exchanger;
private char[] buffer = null;
private char index = 0;
private final Random random;
public ProducerThread(Exchanger<char[]> exchanger, char[] buffer, long seed) {
super("ProducerThread");
this.exchanger = exchanger;
this.buffer = buffer;
this.random = new Random(seed);
}
public void run() {
try {
while (true) {
// 向缓冲区填充字符
for (int i = 0; i < buffer.length; i++) {
buffer[i] = nextChar();
System.out.println(Thread.currentThread().getName() + ": " + buffer[i] + " -> ");
}
// 交换缓冲区
System.out.println(Thread.currentThread().getName() + ": BEFORE exchange");
buffer = exchanger.exchange(buffer);
System.out.println(Thread.currentThread().getName() + ": AFTER exchange");
}
} catch (InterruptedException e) {
}
}
// 生成字符
private char nextChar() throws InterruptedException {
char c = (char)('A' + index % 26);
index++;
Thread.sleep(random.nextInt(1000));
return c;
}
}
ConsumerThread
package pattern.ProducerConsumer.exchanger;
import java.util.Random;
import java.util.concurrent.Exchanger;
public class ConsumerThread extends Thread {
private final Exchanger<char[]> exchanger;
private char[] buffer = null;
private final Random random;
public ConsumerThread(Exchanger<char[]> exchanger, char[] buffer, long seed) {
super("ConsumerThread");
this.exchanger = exchanger;
this.buffer = buffer;
this.random = new Random(seed);
}
public void run() {
try {
while (true) {
// 交换缓冲区
System.out.println(Thread.currentThread().getName() + ": BEFORE exchange");
buffer = exchanger.exchange(buffer);
System.out.println(Thread.currentThread().getName() + ": AFTER exchange");
// 从缓冲区中取出字符
for (int i = 0; i < buffer.length; i++) {
System.out.println(Thread.currentThread().getName() + ": -> " + buffer[i]);
Thread.sleep(random.nextInt(1000));
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}