package cn.org.rapid_framework.io; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import cn.org.rapid_framework.io.AsyncExceptinHandler.DefaultAsyncExceptinHandler; /** * * 异步的输出流 * 使用示例: * <pre> * BufferedOutputStream output = new BufferedOutputStream(new AsyncOutputStream(new FileOutputStream("c:/debug.log"))); * output.write("foo".getBytes()); * </pre> * @author badqiu */ public class AsyncOutputStream extends OutputStream{ private final static byte[] CLOSED_SIGNEL = new byte[0]; private DataProcessorThread dataProcessor; private boolean isClosed = false; private boolean isStartd = false; OutputStream output; BlockingQueue queue; public AsyncOutputStream(OutputStream output) { this(output,new ArrayBlockingQueue(50000)); } public AsyncOutputStream(OutputStream output, BlockingQueue queue) { super(); if(output == null) throw new NullPointerException(); if(queue == null) throw new NullPointerException(); this.output = output; this.queue = queue; this.dataProcessor = new DataProcessorThread(); } public void start() { this.dataProcessor.start(); isStartd = true; } private AsyncExceptinHandler asyncExceptinHandler = new DefaultAsyncExceptinHandler(); private static long threadSeqNumber; private static synchronized long nextThreadID() { return ++threadSeqNumber; } private class DataProcessorThread extends Thread { private boolean enabled = true; private boolean hasRuned = false; DataProcessorThread() { super("AsyncOutputStream.DataProcessorThread-"+nextThreadID()); setDaemon(true); } public void run() { hasRuned = true; while (this.enabled || !queue.isEmpty()) { Object buf; try { buf = queue.take(); } catch (InterruptedException e) { // e.printStackTrace(); continue; } if(buf == CLOSED_SIGNEL) { return; } try { if(buf instanceof Integer) { output.write((Integer)buf); }else { output.write((byte[])buf); } } catch (IOException e) { asyncExceptinHandler.handle(e); } } } } @Override public void write(int b) throws IOException { if(!isStartd) throw new IOException("must start() before wirte()"); if(isClosed) throw new IOException("output is closed"); synchronized (this) { try { queue.put(b); } catch (InterruptedException e) { throw new IOException("AsyncOutputStream occer InterruptedException error"); } } } @Override public void write(byte[] b, int off, int len) throws IOException { if(!isStartd) throw new IOException("must start() before wirte()"); if (b == null) throw new NullPointerException(); synchronized (this) { if(isClosed) throw new IOException("output is closed"); try { queue.put(BufferCopyUtils.copyBuffer(b,off,len)); } catch (InterruptedException e) { throw new IOException("AsyncOutputStream occer InterruptedException error"); } } } @Override public void flush() throws IOException { } public void forceFlush() throws IOException { synchronized (this) { // wait until dataQueue is empty, before calling flush() while (queue.size() > 0) { try { wait(100); } catch (InterruptedException e) { } } output.flush(); } } @Override public void close() throws IOException { synchronized (this) { try { isClosed = true; dataProcessor.enabled = false; if(queue.isEmpty()) { queue.offer(CLOSED_SIGNEL); } try { dataProcessor.join(); } catch (InterruptedException e) { //ignore } if(!dataProcessor.hasRuned) { dataProcessor.run(); } }finally { output.close(); } } } public void setAsyncExceptinHandler(AsyncExceptinHandler asyncExceptinHandler) { if(asyncExceptinHandler == null) throw new NullPointerException(); this.asyncExceptinHandler = asyncExceptinHandler; } }