功能
两个线程交换数据
模式
生产者消费者模式
业务场景:
整理数据库表A数据,并将整理结果存储到表B
单线程思路:查询表A —> 整理数据 —> 插入到表B
多线程思路:线程A查询表A —> 整理数据 —> 将数据写入缓存区
线程B读取缓存区数据 —> 将数据写入表B
解析
Exchanger连接了一对线程,并提供了一个缓冲区和同步点,线程A调用change()时会等待线程B调用change()(这个时候俩线程是啥状态呢?),是生产者消费者模式的简单应用,Exchanger对象实现了channel角色,Producer生产数据装入缓冲区并同步到exchanger,Consumer把空的缓冲区同步到exchanger,并从exchanger里取出数据装入缓冲区,由此完成了一次数据的交换。
例子
Producer
class ExchangerProducer implements Runnable {
private Exchanger<Set<Entity>> exchanger;//Exchanger
private Set<Entity> holder;//内存缓冲区
private Random random = new Random();
//private Date queryDate;//查询日期
private int threshold;//缓冲区的容量阀值
private volatile boolean isDone;//标识统计任务是否完,这个应该放在调度程序里吧
ExchangerProducer(Exchanger<Set<Entity>> exchanger,
Set<Entity> holder, int threshold) {
this.exchanger = exchanger;
this.holder = holder;
this.threshold = threshold;
}
public void run() {
try {
while (!Thread.interrupted()) {
List<Entity> temp = null;
temp = getData();//生产数据
if (temp != null && !temp.isEmpty()) {
//将数据装入缓冲区
System.out.println("生产了数据");
for(Entity e : temp){
System.out.print(e.getData()+",");
}
System.out.println();
holder.addAll(temp);
temp.clear();
}
// 当缓冲区大小大于阀值,执行exchange
if (holder.size() >= threshold) {
holder = exchanger.exchange(holder);
}
}
} catch (InterruptedException e) {
System.out.println("生产线程被中断");
}
exchanger = null;
holder.clear();
holder = null;
}
private List<Entity> getData(){
List<Entity> datas = new ArrayList<Entity>();
for(int i=0;i<random.nextInt(threshold);i++){
datas.add(new Entity(String.valueOf(i)));
}
return datas;
}
}
Consumer
public class ExchangerConsumer implements Runnable{
private Exchanger<Set<Entity>> exchanger;//Exchanger
private Set<Entity> holder;//内存缓冲区
ExchangerConsumer(Exchanger<Set<Entity>> exchanger,Set<Entity> holder) {
this.exchanger = exchanger;
this.holder = holder;
}
public void run() {
List<Entity> temp = null;
try {
while (!Thread.interrupted()){
//先获取数据
holder = exchanger.exchange(holder);
if(holder!=null && !holder.isEmpty()){
temp = readData(holder);
System.out.println("----读取了数据----");
for(Entity e : temp){
System.out.print(e.getData()+",");
}
System.out.println();
temp.clear();
temp=null;
}
holder.clear();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
exchanger = null;
holder.clear();
holder = null;
}
/*
从缓冲区读取数据
*/
private List<Entity> readData(Set<Entity> holder){
List<Entity> datas = new ArrayList<Entity>();
datas.addAll(holder);
return datas;
}
}
调度类
public static void main(String[] args){
Exchanger<Set<Entity>> exchanger = new Exchanger<Set<Entity>>();
//两个线程不可以共用一个holder 不然会导致ConcurrentModificationException
Set<Entity> holderP = new HashSet<Entity>();
Set<Entity> holderC = new HashSet<Entity>();
new Thread(new ExchangerProducer(exchanger,holderP,10)).start();
new Thread(new ExchangerConsumer(exchanger,holderC)).start();
}