Java的通过管道来实现线程通信

前言与一点思考

最近使用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,

并一直阻塞,因为只有十个读者在读,只能消费管道的十个数据,所以程序会一直阻塞。

发布了169 篇原创文章 · 获赞 224 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/sureSand/article/details/86525419