前言与一点思考
最近使用golang的channel并发编程非常爽,又快又方便还不用考虑什么线程不安全的问题,同时在想老相好Java的channel类似实现有没有呢?
Java四种通信方式,分别是synchronized关键字,while(true)轮询,wait和notify以及java.io.Pipe,实际上这个java.io.Pipe和go的channel逻辑是相似的。
Java管道的认识
PipedWriter(允许任务向管道写),和PipedReader(允许不同任务从同一管道中读取)。管道也可以理解为一个缓冲区,将要读写的内容存入到管道,输入输出都要从这个管道去操作,管道提供了一个封装好的解决方案。
代码
package cn.com.controller;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author wangjie
* @version 2018/11/21
* 任务间使用管道进行输入输出
*/
class Sender implements Runnable{
private Random random = new Random(47);
private PipedWriter out = new PipedWriter();
public PipedWriter getPipedWriter(){ return out; }
@Override
public void run(){
try{
for(int i=0;i<20;i++){
out.write(i);
//随机休眠500以内毫秒
TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
}
}catch(IOException e){
System.out.println(e + " Sender write exception");
}catch(InterruptedException e){
System.out.println(e + " Sender sleep interrupt");
}
}
}
class Receiver implements Runnable{
private PipedReader in;
public Receiver(Sender sender) throws IOException{
in = new PipedReader(sender.getPipedWriter());
}
@Override
public void run(){
try{
System.out.println("Read: " + (int)in.read() + ",");
}catch(IOException e){
System.out.println(e + " Receiver read exception");
}
}
}
public class TestPieIo {
public static void main(String[] args) throws Exception{
Sender sender = new Sender();
Receiver receiver = new Receiver(sender);
ExecutorService exec = Executors.newFixedThreadPool(4);
exec.execute(sender);
for (int i=0;i<10;i++) {
exec.execute(receiver);
}
//休眠40秒钟后中断
TimeUnit.SECONDS.sleep(40);
exec.shutdownNow();
}
}
输出:
Read: 0,
Read: 1,
Read: 2,
Read: 3,
Read: 4,
Read: 5,
Read: 6,
Read: 7,
Read: 8,
Read: 9,
并一直阻塞,因为只有十个读者在读,只能消费管道的十个数据,所以程序会一直阻塞。