Java_io体系之PipedWriter、PipedReader简介、走进源码及示例——14
Java_io体系之PipedWriter、PipedReader简介、走进源码及示例——14
——管道字符输出流、必须建立在管道输入流之上、所以先介绍管道字符输出流。可以先看示例或者总结、总结写的有点Q、不喜可无视、有误的地方指出则不胜感激。
一:PipedWriter
1、类功能简介:
管道字符输出流、用于将当前线程的指定字符写入到与此线程对应的管道字符输入流中去、所以PipedReader(pr)、PipedWriter(pw)必须配套使用、缺一不可。管道字符输出流的本质就是调用pr中的方法将字符或者字符数组写入到pr中、这一点是与众不同的地方。所以pw中的方法很少也很简单、主要就是负责将传入的pr与本身绑定、配对使用、然后就是调用绑定的pr的写入方法、将字符或者字符数组写入到pr的缓存字符数组中。
2、PipedWriter API简介:
A:关键字
private PipedReader sink; 与此PipedWriter绑定的PipedReader
private boolean closed = false; 标示此流是否关闭。
B:构造方法
PipedWriter(PipedReader snk) 根据传入的PipedReader构造pw、并将pr与此pw绑定
PipedWriter() 创建一个pw、在使用之前必须与一个pr绑定
C:一般方法
synchronized void connect(PipedReader snk) 将此pw与一个pr绑定 void close() 关闭此流。 synchronized void connect(PipedReader snk) 将此pw与一个pr绑定 synchronized void flush() flush此流、唤醒pr中所有等待的方法。 void write(int c) 将一个整数写入到与此pw绑定的pr的缓存字符数组buf中去 void write(char cbuf[], int off, int len) 将cbuf的一部分写入pr的buf中去
3、源码分析
package com.chy.io.original.code;
import java.io.IOException;
public class PipedWriter extends Writer {
//与此PipedWriter绑定的PipedReader
private PipedReader sink;
//标示此流是否关闭。
private boolean closed = false;
/**
* 根据传入的PipedReader构造pw、并将pr与此pw绑定
*/
public PipedWriter(PipedReader snk) throws IOException {
connect(snk);
}
/**
* 创建一个pw、在使用之前必须与一个pr绑定
*/
public PipedWriter() {
}
/**
* 将此pw与一个pr绑定
*/
public synchronized void connect(PipedReader snk) throws IOException {
if (snk == null) {
throw new NullPointerException();
} else if (sink != null || snk.connected) {
throw new IOException("Already connected");
} else if (snk.closedByReader || closed) {
throw new IOException("Pipe closed");
}
sink = snk;
snk.in = -1;
snk.out = 0;
snk.connected = true;
}
/**
* 将一个整数写入到与此pw绑定的pr的缓存字符数组buf中去
*/
public void write(int c) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
}
sink.receive(c);
}
/**
* 将cbuf的一部分写入pr的buf中去
*/
public void write(char cbuf[], int off, int len) throws IOException {
if (sink == null) {
throw new IOException("Pipe not connected");
} else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
throw new IndexOutOfBoundsException();
}
sink.receive(cbuf, off, len);
}
/**
* flush此流、唤醒pr中所有等待的方法。
*/
public synchronized void flush() throws IOException {
if (sink != null) {
if (sink.closedByReader || closed) {
throw new IOException("Pipe closed");
}
synchronized (sink) {
sink.notifyAll();
}
}
}
/**
* 关闭此流。
*/
public void close() throws IOException {
closed = true;
if (sink != null) {
sink.receivedLast();
}
}
}
4、实例演示:
因为PipedWriter必须与PipedReader结合使用、所以将两者的示例放在一起。
二:PipedReader
1、类功能简介:
管道字符输入流、用于读取对应绑定的管道字符输出流写入其内置字符缓存数组buffer中的字符、借此来实现线程之间的通信、pr中专门有两个方法供pw调用、receive(char c)、receive(char[] b, int off, intlen)、使得pw可以将字符或者字符数组写入pr的buffer中、
2、PipedReader API简介:
A:关键字
boolean closedByWriter = false; 标记PipedWriter是否关闭
boolean closedByReader = false; 标记PipedReader是否关闭
boolean connected = false; 标记PipedWriter与标记PipedReader是否关闭的连接是否关闭
Thread readSide; 拥有PipedReader的线程
Thread writeSide; 拥有PipedWriter的线程
private static final int DEFAULT_PIPE_SIZE = 1024; 用于循环存放PipedWriter写入的字符数组的默认大小
char buffer[]; 用于循环存放PipedWriter写入的字符数组
int in = -1; buf中下一个存放PipedWriter调用此PipedReader的receive(int c)时、c在buf中存放的位置的下标。此为初始状态、即buf中没有字符
int out = 0; buf中下一个被读取的字符的下标
B:构造方法
PipedReader(PipedWriter src) 使用默认的buf的大小和传入的pw构造pr PipedReader(PipedWriter src, int pipeSize) 使用指定的buf的大小和传入的pw构造pr PipedReader() 使用默认大小构造pr PipedReader(int pipeSize) 使用指定大小构造pr
C:一般方法
void close() 清空buf中数据、关闭此流。 void connect(PipedWriter src) 调用与此流绑定的pw的connect方法、将此流与对应的pw绑定 synchronized boolean ready() 查看此流是否可读 synchronized int read() 从buf中读取一个字符、以整数形式返回 synchronized int read(char cbuf[], int off, int len) 将buf中读取一部分字符到cbuf中。 synchronized void receive(int c) pw调用此流的此方法、向pr的buf以整数形式中写入一个字符。 synchronized void receive(char c[], int off, int len) 将c中一部分字符写入到buf中。 synchronized void receivedLast() 提醒所有等待的线程、已经接收到了最后一个字符。
3、源码分析
package com.chy.io.original.code;
import java.io.IOException;
public class PipedReader extends Reader {
boolean closedByWriter = false;
boolean closedByReader = false;
boolean connected = false;
Thread readSide;
Thread writeSide;
/**
* 用于循环存放PipedWriter写入的字符数组的默认大小
*/
private static final int DEFAULT_PIPE_SIZE = 1024;
/**
* 用于循环存放PipedWriter写入的字符数组
*/
char buffer[];
/**
* buf中下一个存放PipedWriter调用此PipedReader的receive(int c)时、c在buf中存放的位置的下标。
* in为-1时、说明buf中没有可读取字符、in=out时已经存满了。
*/
int in = -1;
/**
* buf中下一个被读取的字符的下标
*/
int out = 0;
/**
* 使用默认的buf的大小和传入的pw构造pr
*/
public PipedReader(PipedWriter src) throws IOException {
this(src, DEFAULT_PIPE_SIZE);
}
/**
* 使用指定的buf的大小和传入的pw构造pr
*/
public PipedReader(PipedWriter src, int pipeSize) throws IOException {
initPipe(pipeSize);
connect(src);
}
/**
* 使用默认大小构造pr
*/
public PipedReader() {
initPipe(DEFAULT_PIPE_SIZE);
}
/**
* 使用指定大小构造pr
*/
public PipedReader(int pipeSize) {
initPipe(pipeSize);
}
//初始化buf大小
private void initPipe(int pipeSize) {
if (pipeSize <= 0) {
throw new IllegalArgumentException("Pipe size <= 0");
}
buffer = new char[pipeSize];
}
/**
* 调用与此流绑定的pw的connect方法、将此流与对应的pw绑定
*/
public void connect(PipedWriter src) throws IOException {
src.connect(this);
}
/**
* pw调用此流的此方法、向pr的buf以整数形式中写入一个字符。
*/
synchronized void receive(int c) throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByWriter || closedByReader) {
throw new IOException("Pipe closed");
} else if (readSide != null && !readSide.isAlive()) {
throw new IOException("Read end dead");
}
writeSide = Thread.currentThread();
while (in == out) {
if ((readSide != null) && !readSide.isAlive()) {
throw new IOException("Pipe broken");
}
//buf中写入的被读取完、唤醒所有此对象监控的线程其他方法、如果一秒钟之后还是满值、则再次唤醒其他方法、直到buf中被读取。
notifyAll();
try {
wait(1000);
} catch (InterruptedException ex) {
throw new java.io.InterruptedIOException();
}
}
//buf中存放第一个字符时、将字符在buf中存放位置的下标in初始化为0、读取的下标也初始化为0、准备接受写入的第一个字符。
if (in < 0) {
in = 0;
out = 0;
}
buffer[in++] = (char) c;
//如果buf中放满了、则再从头开始存放。
if (in >= buffer.length) {
in = 0;
}
}
/**
* 将c中一部分字符写入到buf中。
*/
synchronized void receive(char c[], int off, int len) throws IOException {
while (--len >= 0) {
receive(c[off++]);
}
}
/**
* 提醒所有等待的线程、已经接收到了最后一个字符、PipedWriter已关闭。用于PipedWriter的close()方法.
*/
synchronized void receivedLast() {
closedByWriter = true;
notifyAll();
}
/**
* 从buf中读取一个字符、以整数形式返回
*/
public synchronized int read() throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByReader) {
throw new IOException("Pipe closed");
} else if (writeSide != null && !writeSide.isAlive() && !closedByWriter && (in < 0)) {
throw new IOException("Write end dead");
}
readSide = Thread.currentThread();
int trials = 2;
while (in < 0) {
if (closedByWriter) {
/* closed by writer, return EOF */
return -1;
}
if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
throw new IOException("Pipe broken");
}
/* might be a writer waiting */
notifyAll();
try {
wait(1000);
} catch (InterruptedException ex) {
throw new java.io.InterruptedIOException();
}
}
int ret = buffer[out++];
if (out >= buffer.length) {
out = 0;
}
if (in == out) {
/* now empty */
in = -1;
}
return ret;
}
/**
* 将buf中读取一部分字符到cbuf中。
*/
public synchronized int read(char cbuf[], int off, int len) throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByReader) {
throw new IOException("Pipe closed");
} else if (writeSide != null && !writeSide.isAlive() && !closedByWriter && (in < 0)) {
throw new IOException("Write end dead");
}
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
/* possibly wait on the first character */
int c = read();
if (c < 0) {
return -1;
}
cbuf[off] = (char)c;
int rlen = 1;
while ((in >= 0) && (--len > 0)) {
cbuf[off + rlen] = buffer[out++];
rlen++;
//如果读取的下一个字符下标大于buffer的size、则重置out、从新开始从第一个开始读取。
if (out >= buffer.length) {
out = 0;
}
//如果下一个写入字符的下标与下一个被读取的下标相同、则清空buf
if (in == out) {
/* now empty */
in = -1;
}
}
return rlen;
}
/**
* 查看此流是否可读、看各个线程是否关闭、以及buffer中是否有可供读取的字符。
*/
public synchronized boolean ready() throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByReader) {
throw new IOException("Pipe closed");
} else if (writeSide != null && !writeSide.isAlive()
&& !closedByWriter && (in < 0)) {
throw new IOException("Write end dead");
}
if (in < 0) {
return false;
} else {
return true;
}
}
/**
* 清空buf中数据、关闭此流。
*/
public void close() throws IOException {
in = -1;
closedByReader = true;
}
}
4、实例演示:
package com.chy.io.original.thread; import java.io.IOException;
import java.io.PipedWriter; @SuppressWarnings("all")
public class CharSenderThread implements Runnable {
private PipedWriter pw = new PipedWriter(); public PipedWriter getPipedWriter(){
return pw;
}
@Override
public void run() {
//sendOneChar();
//sendShortMessage();
sendLongMessage();
} private void sendOneChar(){
try {
pw.write("a".charAt(0));
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
} private void sendShortMessage() {
try {
pw.write("this is a short message from CharSenderThread !".toCharArray());
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
} private void sendLongMessage(){
try {
char[] b = new char[1028];
//生成一个长度为1028的字符数组、前1020个是1、后8个是2。
for(int i=0; i<1020; i++){
b[i] = 'a';
}
for (int i = 1020; i <1028; i++) {
b[i] = 'b';
}
pw.write(b);
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
用于接收字符的线程: CharReceiveThread
package com.chy.io.original.thread; import java.io.IOException;
import java.io.PipedReader; @SuppressWarnings("all")
public class CharReceiverThread extends Thread { private PipedReader pr = new PipedReader(); public PipedReader getPipedReader(){
return pr;
}
@Override
public void run() {
//receiveOneChar();
//receiveShortMessage();
receiverLongMessage();
} private void receiveOneChar(){
try {
int n = pr.read();
System.out.println(n);
pr.close();
} catch (IOException e) {
e.printStackTrace();
}
} private void receiveShortMessage() {
try {
char[] b = new char[1024];
int n = pr.read(b);
System.out.println(new String(b, 0, n));
pr.close(); } catch (IOException e) {
e.printStackTrace();
}
} private void receiverLongMessage(){
try {
char[] b = new char[2048];
int count = 0;
while(true){
count = pr.read(b);
for (int i = 0; i < count; i++) {
System.out.print(b[i]);
}
if(count == -1)
break;
}
pr.close(); } catch (IOException e) {
e.printStackTrace();
}
} }
package com.chy.io.original.test; import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter; import com.chy.io.original.thread.CharReceiverThread;
import com.chy.io.original.thread.CharSenderThread; public class PipedWriterAndPipedReaderTest {
public static void main(String[] args) throws IOException{
CharSenderThread cst = new CharSenderThread();
CharReceiverThread crt = new CharReceiverThread();
PipedWriter pw = cst.getPipedWriter();
PipedReader pr = crt.getPipedReader(); pw.connect(pr); /**
* 想想为什么下面这样写会报Piped not connect异常 ?
*/
//new Thread(new CharSenderThread()).start();
//new CharReceiverThread().start(); new Thread(cst).start();
crt.start();
}
}
总结:
PipedReader、PipedWriter两者的结合如鸳鸯一般、离开哪一方都不能继续存在、同时又如连理枝一般、PipedWriter先通过connect(PipedReader sink)来确定关系、并初始化PipedReader状态、告诉PipedReader只能属于这个PipedWriter、connect =true、当想赠与PipedReader字符时、就直接调用receive(char c) 、receive(char[] b, int off, int len)来将字符或者字符数组放入pr的存折buffer中。站在PipedReader角度上、看上哪个PipedWriter时就暗示pw、将主动权交给pw、调用pw的connect将自己给他去登记。当想要花(将字符读取到程序中)字符了就从buffer中拿、但是自己又没有本事挣字符、所以当buffer中没有字符时、自己就等着、并且跟pw讲没有字符了、pw就会向存折(buffer)中存字符、当然、pw不会一直不断往里存、当存折是空的时候也不会主动存、怕花冒、就等着pr要、要才存。过到最后两个只通过buffer来知道对方的存在与否、每次从buffer中存或者取字符时都会看看对方是否安康、若安好则继续生活、若一方不在、则另一方也不愿独存!
更多IO内容:java_io 体系之目录
Java_io体系之PipedWriter、PipedReader简介、走进源码及示例——14的更多相关文章
- Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例——16
Java_io体系之BufferedWriter.BufferedReader简介.走进源码及示例——16 一:BufferedWriter 1.类功能简介: BufferedWriter.缓存字符输 ...
- Java_io体系之RandomAccessFile简介、走进源码及示例——20
Java_io体系之RandomAccessFile简介.走进源码及示例——20 RandomAccessFile 1. 类功能简介: 文件随机访问流.关心几个特点: 1.他实现的接口不再 ...
- java io系列13之 BufferedOutputStream(缓冲输出流)的认知、源码和示例
本章内容包括3个部分:BufferedOutputStream介绍,BufferedOutputStream源码,以及BufferedOutputStream使用示例. 转载请注明出处:http:// ...
- Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装
原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...
- Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘
Scala 深入浅出实战经典 第41讲:List继承体系实现内幕和方法操作源码揭秘 package com.parllay.scala.dataset /** * Created by richard ...
- ThreadLocal 简介 案例 源码分析 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Java生鲜电商平台-电商会员体系系统的架构设计与源码解析
Java生鲜电商平台-电商会员体系系统的架构设计与源码解析 说明:Java生鲜电商平台中会员体系作为电商平台的基础设施,重要性不容忽视.我去年整理过生鲜电商中的会员系统,但是比较粗,现在做一个最好的整 ...
- java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例
本章内容包括3个部分:BufferedInputStream介绍,BufferedInputStream源码,以及BufferedInputStream使用示例. 转载请注明出处:http://www ...
- java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
本章介绍DataOutputStream.我们先对DataOutputStream有个大致认识,然后再深入学习它的源码,最后通过示例加深对它的了解. 转载请注明出处:http://www.cnblog ...
随机推荐
- 《fullPage.js》创建全屏滚动的网站
插件介绍 fullPage.js是一个简单易用的插件,创建全屏滚动的网站(也被称为单页网站).它允许全屏滚动创建网站,以及添加内部滑块. 浏览器兼容性 主要功能 支持鼠标滚动 支持前进后退和键盘控制 ...
- 跨域信息传递postMessage
var sendToParent = function(event, data, listener) { var message = { event: event, data: data, liste ...
- spring-data-mongodb一个系统xml文件里面配置两个数据源
spring-data-mongodb一个系统xml文件里面配置两个数据源 参考文档如下: http://www.iteye.com/problems/92789 http://stackoverfl ...
- jQuery三种事件绑定方式.bind(),.live(),.delegate()
.bind(), .live(), 和 .delegate()之间的区别并不明显.但是理解它们的不同之处有助于写出更简洁的代码,并防止我们的交互程序中出现没有预料到的bug. 基础 DOM树 首先,图 ...
- 关于android:configChanges小结
有段时间没更新博客了,做个音乐播放器遇到了坑,暂放来学习一个开源小项目
- MyEclipse内存不足的问题
今早打开MyEclipse莫名其妙弹出提示框,然后我各种搜索,用了网上能查到的各种办法去试图解决问题,方法包括但不限于 修改eclipse.ini .设置Default VM Arguments . ...
- Qt 数据库创建表失败原因之数据库关键字
本人数据库新手,在创建表时出现问题,最后经查证,找出问题所在.下面的程序是部分节选,在创建数据库表的时候,起先使用的L24的CreateDB,经测试,一直输出 Create testResult Fa ...
- Ubuntu下MySQL配置为外网访问
Ububtu安装MySQL后默认外网无法连接,但是很多时候我们想要在外网访问方便管理.在这里,简单叙述一下自己在配置过程中的操作,步骤如下: 以root身份登入mysql mysql -u root ...
- JAVA-POI实现EXCEL的读写
想要完成JAVA读写EXCEL,首先需要JAVA-POI包的支持,百度搜索即可找到资源,不再赘述: POI-新增EXCEL并输入内容 package com.gsh.test.poi; import ...
- bat命令中的变量声明及使用
在bat文件中声明变量的方式如下: set xxx_variant_name=yyyyyyyyyyyy move D:\abc\efg\test.txt %xxx_variant_name%\test ...