I've written background InputStream (and OutputStream) implementations that wrap other streams, and read ahead on a background thread, primarily allowing for decompression/compression to happen in different threads from the processing of the decompressed stream.
It's a fairly standard producer/consumer model.
This seems like an easy way to make good use of multi-core CPUs with simple processes that read, process, and write data, allowing for more efficient use of both CPU and disk resources. Perhaps 'efficient' isn't the best word, but it provides higher utilisation, and of more interest to me, reduced runtimes, compared to reading directly from a ZipInputStream and writing directly to a ZipOutputStream.
I'm happy to post the code, but my question is whether I'm reinventing something readily available in existing (and more heavily exercised) libraries?
Edit - posting code...
My code for the BackgroundInputStream is below (the BackgroundOutputStream is very similar), but there are aspects of it that I'd like to improve.
It looks like I'm working far too hard to pass buffers back and forward.
If the calling code throws away references to the BackgroundInputStream, the backgroundReaderThread will hang around forever.
Signalling eof needs improving.
Exceptions should be propagated to the foreground thread.
I'd like to allow using a thread from a provided Executor.
The close() method should signal the background thread, and shouldn't close the wrapped stream, as the wrapped stream should be owned by the background thread that reads from it.
Doing silly things like reading after closing should be catered for appropriately.
package nz.co.datacute.io;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;
public class BackgroundInputStream extends InputStream {
private static final int DEFAULT_QUEUE_SIZE = 1;
private static final int DEFAULT_BUFFER_SIZE = 64*1024;
private final int queueSize;
private final int bufferSize;
private volatile boolean eof = false;
private LinkedBlockingQueue<byte[]> bufferQueue;
private final InputStream wrappedInputStream;
private byte[] currentBuffer;
private volatile byte[] freeBuffer;
private int pos;
public BackgroundInputStream(InputStream wrappedInputStream) {
this(wrappedInputStream, DEFAULT_QUEUE_SIZE, DEFAULT_BUFFER_SIZE);
}
public BackgroundInputStream(InputStream wrappedInputStream,int queueSize,int bufferSize) {
this.wrappedInputStream = wrappedInputStream;
this.queueSize = queueSize;
this.bufferSize = bufferSize;
}
#Override
public int read() throws IOException {
if (bufferQueue == null) {
bufferQueue = new LinkedBlockingQueue<byte[]>(queueSize);
BackgroundReader backgroundReader = new BackgroundReader();
Thread backgroundReaderThread = new Thread(backgroundReader, "Background InputStream");
backgroundReaderThread.start();
}
if (currentBuffer == null) {
try {
if ((!eof) || (bufferQueue.size() > 0)) {
currentBuffer = bufferQueue.take();
pos = 0;
} else {
return -1;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int b = currentBuffer[pos++];
if (pos == currentBuffer.length) {
freeBuffer = currentBuffer;
currentBuffer = null;
}
return b;
}
#Override
public int available() throws IOException {
if (currentBuffer == null) return 0;
return currentBuffer.length;
}
#Override
public void close() throws IOException {
wrappedInputStream.close();
currentBuffer = null;
freeBuffer = null;
}
class BackgroundReader implements Runnable {
#Override
public void run() {
try {
while (!eof) {
byte[] newBuffer;
if (freeBuffer != null) {
newBuffer = freeBuffer;
freeBuffer = null;
} else {
newBuffer = new byte[bufferSize];
}
int bytesRead = 0;
int writtenToBuffer = 0;
while (((bytesRead = wrappedInputStream.read(newBuffer, writtenToBuffer, bufferSize - writtenToBuffer)) != -1) && (writtenToBuffer < bufferSize)) {
writtenToBuffer += bytesRead;
}
if (writtenToBuffer > 0) {
if (writtenToBuffer < bufferSize) {
newBuffer = Arrays.copyOf(newBuffer, writtenToBuffer);
}
bufferQueue.put(newBuffer);
}
if (bytesRead == -1) {
eof = true;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Sounds interesting. I've never run across anything that does this out of the box but it makes perfect sense to try and use an idle core for the compression if it's available.
Perhaps you could make use of Commons I/O - it is a well tested lib which could help handle some of the more boring stuff and let you focus on extending the cool parallel parts. Maybe you could even contribute your code to the Commons project ;-)
I'd be interested. I've thought through a similar project, but couldn't figure out how to handle pieces that finish compression out of order.
Related
I've a small android library which handles a serial port, it has basic functionality like open, read, write and close.
I have made an applications that uses this library to write on the serial port and read the responses, within this application there is a thread that periodically opens the serial port asks for the status get the response and close the serial port.
I want to protect the serial communication in a way that if the main thread opens the communication the secondary thread that only checks the status can not open it and wait for the main thread to finish.
class SerialChannel extends Channel
{
private SerialPortUtility serialPortUtility;
private static final String SERIAL_FILE = "/dev/ttyMT2";
private static final String CONTROL_FILE = "/sys/devices/platform/file";
private static final String UNKNOWN_COMMAND = "UNKNOWN COMMAND";
private FileOutputStream fileOutputStream;
private FileInputStream fileInputStream;
#Override
public void open() throws CommunicationException
{
try
{
if (isSerialOpened() != SerialStatus.Open)
{
toggleSerial(SerialStatus.Open.getStatus());
Thread.sleep(100);
}
serialPortUtility = getSerialPortUtility();
fileInputStream = (FileInputStream) serialPortUtility.getInputStream();
fileOutputStream = (FileOutputStream) serialPortUtility.getOutputStream();
currentProcess = Optional.of(Thread.currentThread().getId());
Thread.sleep(500);
}
catch (IOException | InterruptedException e)
{
throw new CommunicationException(e.getMessage());
}
}
#Override
public void close() throws CommunicationException
{
if (serialPortUtility == null)
{
throw new CommunicationException("SerialPort is null");
}
try
{
toggleSerial(SerialStatus.Close.getStatus());
fileOutputStream.close();
fileInputStream.close();
serialPortUtility.close();
fileInputStream = null;
fileOutputStream = null;
serialPortUtility = null;
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
}
#Override
public void send(byte[] buffer, int timeout, int length) throws CommunicationException
{
if (fileOutputStream == null)
{
throw new CommunicationException("Problem while sending data!");
}
try
{
fileOutputStream.write(buffer);
fileOutputStream.flush();
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
}
#Override
public byte[] receive(int length, int timeout) throws CommunicationException
{
StringBuilder stringBuilder = new StringBuilder();
byte[] buffer = new byte[length];
int ret;
int totalSize = 0;
if (fileInputStream == null)
{
throw new CommunicationException("FileInputStream is null!");
}
try
{
long millisStart = Calendar.getInstance().getTimeInMillis();
boolean timeoutReached;
while (true)
{
timeoutReached = (Calendar.getInstance().getTimeInMillis() - millisStart > timeout * 1000);
if (fileInputStream.available() <= 0 && timeoutReached)
{
expectingResult = false;
throw new CommunicationException("Error");
}
else if (fileInputStream.available() > 0)
{
break;
}
}
millisStart = Calendar.getInstance().getTimeInMillis();
while (totalSize != length && (ret = fileInputStream.read(buffer)) != -1)
{
String received = new String(buffer);
stringBuilder.append(received);
if(buffer.length == 15 && received.equals(UNKNOWN_COMMAND))
{
break;
}
totalSize += ret;
}
expectingResult = false;
}
catch (IOException e)
{
throw new CommunicationException(e.getMessage());
}
return stringBuilder.toString().getBytes();
}
private SerialPortUtility getSerialPortUtility() throws IOException
{
if (serialPortUtility == null)
{
File file = new File(SERIAL_FILE);
int baudRate = 115200;
return new SerialPortUtility(file, baudRate, 0);
}
return serialPortUtility;
}
private void toggleSerial(String data) throws IOException
{
FileOutputStream fos = new FileOutputStream(new File(CONTROL_FILE));
fos.write(data.getBytes());
fos.flush();
fos.close();
}
private SerialStatus isSerialOpened() throws IOException
{
byte[] buffer = new byte[1];
FileInputStream fis = new FileInputStream(new File(CONTROL_FILE));
int result = fis.read(buffer);
fis.close();
if (result > -1 && buffer[0] == 1)
{
return SerialStatus.Open;
}
return SerialStatus.Close;
}
}
This class extends custom class Channel that implements an interface with the methods open, close, read, send and implements also AutoCloseable.
Now if I make the open method synchronized any thread that enters here will lock, but will lock until it exits the open method, and when the thread moves to the another method let's say read and stay there until it gets a response, the checker thread will come and enters the open method. Using AutoCloseable the close method will execute and close the serial port communication. If I synchronize an object, there still is a window when the object is not synchronized.
How can I tell the checker thread that the communication is already opened and make him wait until the main thread finish.
Checker looks like this, it is within an timer:
try(Channel ch = CommunicationFactory.getInstance().selectChannel(CommunicationType.SERIAL))
{
ch.open();
//do stuff
}
catch (CommunicationException ex)
{
ex.printStackTrace();
}
The "main" thread looks the same only that it is in an AysncTask.
If additional informations are required please let me know!
Thank you in advance for your effort and time!
How can I tell the checker thread that the communication is already opened and make him wait until the main thread finish.
I don't fully understand your code but the critical thing with threads and locking is to make sure that all threads are calling code that is synchronized on the same object instance.
If I synchronize an object, there still is a window when the object is not synchronized.
Not if you use the same instance of the object. Making each of the public methods in SerialChannel synchronized will make sure that only 1 thread can be using the object at once.
I suspect that your real problem is not about protecting the SerialChannel object but more about race-conditions between the threads. They need to make multiple calls to the methods and they can block each other or interleave in an improper manner.
You can get around this with a couple of changes. You can make the send(...) and receive(...) methods auto-opening. Threads would just call send() or receive() which in turn would internally call open() if the fileInputStream or fileOutputStream was null. The thread would be inside of a synchronized so this would not be interrupted by another thread.
Another completely different model to consider would be to have one thread reading from the serial port and another writing to it that are dedicated to that task -- they would be built into the SerialChannel object. They would share data with the external threads using a read BlockingQueue and a write BlockingQueue. Then the serial port is opened early in your application which starts the IO threads and the external threads never worry about the IO. They just put() and take() from the queues. I typically do this (for example) when reading and writing to the console.
Hope something here helps.
As the title, and assume the size of byte array is no larger than 16 Kbytes.
Currently I am implementing a middleware for MySQL (like MySQL Proxy), which requires high throughput. but the overhead caused by reading data from socket and writing data to socket. For now, I use
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()))
and
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()))
When read data and write, I use
in.read(byte[] b) and out.write(byte[] b, int offset, int len) with out.flush()
Can anyone tell me a better way to do this?
If you're writing byte arrays it doesn't make much difference. The network is the limiting factor, not the API. I think you're already doing it near-optimally. The most significant factor is the size of your socket send buffer in the kernel, and the socket receive buffer at the receiver.
You could investigate NIO and direct buffers, but I doubt you'll see a significant difference. Direct buffers are really for the case where you're just copying between channels, and the rest of NIO is really about scalability rather than performance over an individual channel.
Since you are just forwarding bytes, you could save a little time by not using DataInputStream, and instead just using BufferedInputStream.read() and BufferedOutputStream.write().
As EJP mentions, the network is the limiting factor. But that did not stop me trying to make the fastest implementation I could imagine without using NIO. The thing is, you can read from a socket while you write to another/the same socket. One thread cannot do this (either reads or writes) so multiple threads are needed. But without NIO, that requires a lot of threads (mostly sitting idle waiting on I/O though). NIO is a bit more complicated but is very good at using very few threads when there are a lot of connections with low volume (see the summary on this page of the article that Baldy mentions).
Anyway, below a non-NIO test class that you can update and use to see for yourself what is (not) the limiting factor.
public class SocketForwarder {
public static void main(String[] args) {
try {
new SocketForwarder().forward();
} catch (Exception e) {
e.printStackTrace();
}
}
public static final int portNumber = 54321;
public static final int maxSend = 1024 * 1024 * 100; // 100 MB
public static final int bufSize = 16 * 1024;
public static final int maxBufInMem = 128;
private static final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
private final ExecutorService tp = Executors.newCachedThreadPool();
private final ArrayBlockingQueue<byte[]> bq = new ArrayBlockingQueue<byte[]>(maxBufInMem);
private final CountDownLatch allReceived = new CountDownLatch(1);
private Socket from, to, sender, receiver;
private int bytesSend, bytesReceived;
public void forward() throws Exception {
tp.execute(new Runnable() {
public void run() {
ServerSocket ss = null;
try {
ss = new ServerSocket(portNumber);
from = ss.accept();
to = ss.accept();
} catch (Exception e) {
e.printStackTrace();
} finally {
try { ss.close(); } catch (Exception ignored) {}
}
}
});
sender = new Socket(InetAddress.getLocalHost(), portNumber);
receiver = new Socket(InetAddress.getLocalHost(), portNumber);
// Setup proxy reader.
tp.execute(new Runnable() {
public void run() {
byte[] buf = new byte[bufSize];
try {
InputStream in = from.getInputStream();
int l = 0;
while ((l = in.read(buf)) > 0) {
byte[] bufq = new byte[l];
System.arraycopy(buf, 0, bufq, 0, l);
bq.put(bufq);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
// Setup proxy writer.
tp.execute(new Runnable() {
public void run() {
try {
OutputStream out = to.getOutputStream();
while (true) {
byte[] bufq = bq.take();
out.write(bufq);
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
// Start receiver.
tp.execute(new Runnable() {
public void run() {
byte[] buf = new byte[bufSize];
try {
InputStream in = receiver.getInputStream();
int l = 0;
while (bytesReceived < maxSend && (l = in.read(buf)) > 0) {
bytesReceived += l;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(df.format(new Date()) + " bytes received: " + bytesReceived);
allReceived.countDown();
}
});
// Start sender.
tp.execute(new Runnable() {
public void run() {
Random random = new Random();
try {
OutputStream out = sender.getOutputStream();
System.out.println(df.format(new Date()) + " start sending.");
while (bytesSend < maxSend) {
byte[] buf = new byte[random.nextInt(bufSize)];
out.write(buf);
out.flush();
bytesSend += buf.length;
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Bytes send: " + bytesSend);
}
});
try {
allReceived.await();
} finally {
close(sender);
close(from);
close(to);
close(receiver);
tp.shutdownNow();
}
}
private static void close(Socket s) {
try { s.close(); } catch (Exception ignored) {}
}
}
It took my computer 2 seconds to transfer 100MB locally, expect a lot less when a network is involved.
For the best throughput you're going to want to use NIO and ByteBuffers. NIO keeps most of the work reading and writing to the sockets in native code and so can be much faster.
It is more complex to write good NIO code but depending on what kind of performance you're looking for, it can be worth the effort.
There are some good NIO examples out there along with some good introductions and comparisons. One resource I've used is http://tutorials.jenkov.com/java-nio/index.html.
I have a requirement where I need to read from a set of Blocking queues. The blocking queues are created by the Library I am using. My code has to read from the queues. I don't want to create a reader thread for each of these blocking queues. Rather I want to poll them for availability of data using a single thread (or probably using 2/3 threads at max). As some of the blocking queues might not have data for long time, while some of them may get bursts of data. Polling the queues with small timeout will work, but that is not efficient at all as it still needs to keep looping over all the queues even when some of them are without data for long time. Basically, I am looking for a select/epoll(used on sockets) kind of mechanism on blocking queues. Any clue is really appreciated.
Doing that in Go is real easy though. Below code simulates the same with channels and goroutines:
package main
import "fmt"
import "time"
import "math/rand"
func sendMessage(sc chan string) {
var i int
for {
i = rand.Intn(10)
for ; i >= 0 ; i-- {
sc <- fmt.Sprintf("Order number %d",rand.Intn(100))
}
i = 1000 + rand.Intn(32000);
time.Sleep(time.Duration(i) * time.Millisecond)
}
}
func sendNum(c chan int) {
var i int
for {
i = rand.Intn(16);
for ; i >= 0; i-- {
time.Sleep(20 * time.Millisecond)
c <- rand.Intn(65534)
}
i = 1000 + rand.Intn(24000);
time.Sleep(time.Duration(i) * time.Millisecond)
}
}
func main() {
msgchan := make(chan string, 32)
numchan := make(chan int, 32)
i := 0
for ; i < 8 ; i++ {
go sendNum(numchan)
go sendMessage(msgchan)
}
for {
select {
case msg := <- msgchan:
fmt.Printf("Worked on %s\n", msg)
case x := <- numchan:
fmt.Printf("I got %d \n", x)
}
}
}
I suggest you look into using the JCSP library. The equivalent of Go's select is called Alternative. You would only need one consuming thread, which will not need to poll the incoming channels if it switches on them with Alternative. Therefore this would be an efficient way to multiplex the source data.
It will help a lot if you are able to replace the BlockingQueues with JCSP channels. Channels behave essentially the same but provide a greater degree of flexibility regarding the fan-out or fan-in of sharing of channel ends, and in particular, the use of channels with Alternative.
For an example of usage, here is a fair multiplexer. This example demonstrates a process that fairly multiplexes traffic from its array of input channels to its single output channel. No input channel will be starved, regardless of the eagerness of its competitors.
import org.jcsp.lang.*;
public class FairPlex implements CSProcess {
private final AltingChannelInput[] in;
private final ChannelOutput out;
public FairPlex (final AltingChannelInput[] in, final ChannelOutput out) {
this.in = in;
this.out = out;
}
public void run () {
final Alternative alt = new Alternative (in);
while (true) {
final int index = alt.fairSelect ();
out.write (in[index].read ());
}
}
}
Note that if priSelect were used above, higher-indexed channels would be starved if lower-indexed channels were continually demanding service. Or instead of fairSelect, select could be used, but then no starvation analysis is possible. The select mechanism should only be used when starvation is not an issue.
Freedom from Deadlock
As with Go, a Java program using channels must be designed not to deadlock. The implementation of low-level concurrency primitives in Java is very hard to get right and you need something dependable. Fortunately, Alternative has been validated by formal analysis, along with the JCSP channels. This makes it a solid reliable choice.
Just to clear up on slight point of confusion, the current JCSP version is 1.1-rc5 in the Maven repos, not what the website says.
An another choice is here for Java6+
A BlockingDeque implementation class:
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicLong;
class GoChannelPool {
private final static GoChannelPool defaultInstance = newPool();
private final AtomicLong serialNumber = new AtomicLong();
private final WeakHashMap<Long, WeakReference<GoChannel>> channelWeakHashMap = new WeakHashMap<>();
private final LinkedBlockingDeque<GoChannelObject> totalQueue = new LinkedBlockingDeque<>();
public <T> GoChannel<T> newChannel() {
GoChannel<T> channel = new GoChannel<>();
channelWeakHashMap.put(channel.getId(), new WeakReference<GoChannel>(channel));
return channel;
}
public void select(GoSelectConsumer consumer) throws InterruptedException {
consumer.accept(getTotalQueue().take());
}
public int size() {
return getTotalQueue().size();
}
public int getChannelCount() {
return channelWeakHashMap.values().size();
}
private LinkedBlockingDeque<GoChannelObject> getTotalQueue() {
return totalQueue;
}
public static GoChannelPool getDefaultInstance() {
return defaultInstance;
}
public static GoChannelPool newPool() {
return new GoChannelPool();
}
private GoChannelPool() {}
private long getSerialNumber() {
return serialNumber.getAndIncrement();
}
private synchronized void syncTakeAndDispatchObject() throws InterruptedException {
select(new GoSelectConsumer() {
#Override
void accept(GoChannelObject t) {
WeakReference<GoChannel> goChannelWeakReference = channelWeakHashMap.get(t.channel_id);
GoChannel channel = goChannelWeakReference != null ? goChannelWeakReference.get() : null;
if (channel != null) {
channel.offerBuffer(t);
}
}
});
}
class GoChannel<E> {
// Instance
private final long id;
private final LinkedBlockingDeque<GoChannelObject<E>> buffer = new LinkedBlockingDeque<>();
public GoChannel() {
this(getSerialNumber());
}
private GoChannel(long id) {
this.id = id;
}
public long getId() {
return id;
}
public E take() throws InterruptedException {
GoChannelObject object;
while((object = pollBuffer()) == null) {
syncTakeAndDispatchObject();
}
return (E) object.data;
}
public void offer(E object) {
GoChannelObject<E> e = new GoChannelObject();
e.channel_id = getId();
e.data = object;
getTotalQueue().offer(e);
}
protected void offerBuffer(GoChannelObject<E> data) {
buffer.offer(data);
}
protected GoChannelObject<E> pollBuffer() {
return buffer.poll();
}
public int size() {
return buffer.size();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
channelWeakHashMap.remove(getId());
}
}
class GoChannelObject<E> {
long channel_id;
E data;
boolean belongsTo(GoChannel channel) {
return channel != null && channel_id == channel.id;
}
}
abstract static class GoSelectConsumer{
abstract void accept(GoChannelObject t);
}
}
then we can use it in this way:
GoChannelPool pool = GoChannelPool.getDefaultInstance();
final GoChannelPool.GoChannel<Integer> numberCh = pool.newChannel();
final GoChannelPool.GoChannel<String> stringCh = pool.newChannel();
final GoChannelPool.GoChannel<String> otherCh = pool.newChannel();
ExecutorService executorService = Executors.newCachedThreadPool();
int times;
times = 2000;
final CountDownLatch countDownLatch = new CountDownLatch(times * 2);
final AtomicInteger numTimes = new AtomicInteger();
final AtomicInteger strTimes = new AtomicInteger();
final AtomicInteger defaultTimes = new AtomicInteger();
final int finalTimes = times;
executorService.submit(new Runnable() {
#Override
public void run() {
for (int i = 0; i < finalTimes; i++) {
numberCh.offer(i);
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
executorService.submit(new Runnable() {
#Override
public void run() {
for (int i = 0; i < finalTimes; i++) {
stringCh.offer("s"+i+"e");
try {
Thread.sleep((long) (Math.random() * 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
int otherTimes = 3;
for (int i = 0; i < otherTimes; i++) {
otherCh.offer("a"+i);
}
for (int i = 0; i < times*2 + otherTimes; i++) {
pool.select(new GoChannelPool.GoSelectConsumer() {
#Override
void accept(GoChannelPool.GoChannelObject t) {
// The data order should be randomized.
System.out.println(t.data);
countDownLatch.countDown();
if (t.belongsTo(stringCh)) {
strTimes.incrementAndGet();
return;
}
else if (t.belongsTo(numberCh)) {
numTimes.incrementAndGet();
return;
}
defaultTimes.incrementAndGet();
}
});
}
countDownLatch.await(10, TimeUnit.SECONDS);
/**
The console output of data should be randomized.
numTimes.get() should be 2000
strTimes.get() should be 2000
defaultTimes.get() should be 3
*/
and beware that the select works only if the channels belong to the same GoChannelPool, or just use the default GoChannelPool(however the performance would be lower if too many channels share the same GoChannelPool)
The only way is to replace standard queues with objects of a more functional class, which notifies consumer(s) when datum is inserted in an empty queue. This class still can implement the BlockingQueue interface, so the other side (producer) see no difference. The trick is that put operation should also raise a flag and notify consumer. Consumer, after polling all threads, clears the flag and calls Object.wait().
I remember when I was very new to Java, not knowing threads could share the memory of the process, I would have my threads communicate using (TCP/local) Sockets. Perhaps this can also work.
I believe I have done everything correctly. I create a pipe, pass the sink to a writer thread, register the source on my selector with OP_READ, start my selector. Everything works but as soon as I write something to the sink I get a broken pipe exception. Why !!!??? There is no broken pipe here. I am frustrated. How can I debug / understand what is happening here? Does anyone have a simple pipe example that I can run to test if this is working. A thread writing on the sink and the selector reading it.
EDIT: I pretty much followed the suggestion here. It is hard to find concrete examples of NIO pipes in the Internet.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class SystemOutPipe extends Thread {
public static void main(String[] args)
{
try {
SystemOutPipe sop = new SystemOutPipe();
sop.start();
System.out.println("This message should be redirected to System.err\nNow waiting 5 seconds ...");
Thread.sleep(5000L);
sop.setStopped(true);
sop.join();
} catch (Exception e) {
e.printStackTrace();
}
}
private Selector selector;
private Pipe pipe;
private boolean stopped = false;
public SystemOutPipe() throws IOException {
super("SystemOutPipe");
pipe = Pipe.open();
System.setOut(new PrintStream(new PipeOutputStream(pipe)));
selector = Selector.open();
pipe.source().configureBlocking(false);
pipe.source().register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
}
#Override
public void run() {
try {
while (!isStopped()) {
int n = selector.select(1L);
if (n > 0) {
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isReadable()) {
new ReadHandler(key).run();
}
}
}
}
} catch (Exception e) {
e.printStackTrace(); // writes to System.err !
}
}
public synchronized boolean isStopped() {
return stopped;
}
public synchronized void setStopped(final boolean stopped) {
this.stopped = stopped;
}
public class ReadHandler implements Runnable {
private final SelectionKey key;
public ReadHandler(final SelectionKey key) {
this.key = key;
}
#Override
public void run() {
ByteBuffer bbuf = (ByteBuffer) key.attachment();
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
try
{
int count = 0;
do {
bbuf.clear();
count = channel.read(bbuf);
if (count > 0) System.err.write(bbuf.array(), 0, count);
} while(count > 0);
} catch (IOException e) {
e.printStackTrace();
key.cancel();
}
}
}
public class PipeOutputStream extends OutputStream {
private final Pipe pipe;
public PipeOutputStream(final Pipe pipe) {
this.pipe = pipe;
}
#Override
public void write(final int b) throws IOException {
write(new byte[] { (byte) b });
}
#Override
public void write(final byte[] b) throws IOException {
write(b, 0, b.length);
}
#Override
public void write(final byte[] b, final int off, final int len) throws IOException {
ByteBuffer bbuf = ByteBuffer.wrap(b, off, len);
bbuf.position(len);
bbuf.flip();
int count = 0;
while (count < len) {
int n = pipe.sink().write(bbuf);
if (n == 0) {
// let's wait a bit and not consume cpu
try {
Thread.sleep(1L);
} catch (InterruptedException e) {
throw new IOException(e);
}
}
else count += n;
}
}
}
}
EXCEPTION:
java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcher.write0(Native Method)
at sun.nio.ch.FileDispatcher.write(FileDispatcher.java:39)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:72)
at sun.nio.ch.IOUtil.write(IOUtil.java:43)
at sun.nio.ch.SinkChannelImpl.write(SinkChannelImpl.java:149)
at com.niostuff.util.GCLogInterceptor.fileModified(GCLogInterceptor.java:180)
at net.contentobjects.jnotify.linux.JNotifyAdapterLinux$WatchData.notifyFileModified(Unknown Source)
at net.contentobjects.jnotify.linux.JNotifyAdapterLinux.notifyChangeEvent(Unknown Source)
at net.contentobjects.jnotify.linux.JNotifyAdapterLinux$1.notify(Unknown Source)
at net.contentobjects.jnotify.linux.JNotify_linux.callbackProcessEvent(Unknown Source)
at net.contentobjects.jnotify.linux.JNotify_linux.nativeNotifyLoop(Native Method)
at net.contentobjects.jnotify.linux.JNotify_linux.access$000(Unknown Source)
at net.contentobjects.jnotify.linux.JNotify_linux$1.run(Unknown Source)
Ok, so I found the problem. First thanks for everyone trying to help. Hopefully you will learn from my mistake. The chain of events were:
1 - I was not draining the receiving buffer (the one the source channel reads into) and it eventually got full.
2 - Now that it is full, pipeSourceChannel.read(readBuffer) returns 0 bytes. There is data to be read but It can't read on a full buffer.
3 - That caused the channel to be closed (i was doing that myself on bytesRead == 0) and the BrokenPipe.
One lesson I learned here: PIPES are tricky. I would think that non-blocking concurrent queues are much simpler to use like this guy here once mentioned: Java NIO Pipe vs BlockingQueue
Does anyone have any good suggestions for creating a Pipe object in Java which is both an InputStream and and OutputStream since Java does not have multiple inheritance and both of the streams are abstract classes instead of interfaces?
The underlying need is to have a single object that can be passed to things which need either an InputStream or an OutputStream to pipe output from one thread to input for another.
It seems the point of this question is being missed. If I understand you correctly, you want an object that functions like an InputStream in one thread, and an OutputStream in another to create a means of communicating between the two threads.
Perhaps one answer is to use composition instead of inheritance (which is recommended practice anyway). Create a Pipe which contains a PipedInputStream and a PipedOutputStream connected to each other, with getInputStream() and getOutputStream() methods.
You can't directly pass the Pipe object to something needing a stream, but you can pass the return value of it's get methods to do it.
Does that work for you?
java.io.PipedOutputStream and java.io.PipedInputStream look to be the classes to use for this scenario. They are designed to be used together to pipe data between threads.
If you really want some single object to pass around it would need to contain one of each of these and expose them via getters.
This is a pretty common thing to do, I think. See this question.
Easy way to write contents of a Java InputStream to an OutputStream
You can't create a class which derives both from InputStream and OutputStream because these aren't interfaces and they have common methods and Java doesn't allow multiple inheritance (the compiler doesn't know whether to call InputStream.close() or OutputStream.close() if you call close() on your new object).
The other problem is the buffer. Java wants to allocate a static buffer for the data (which doesn't change). This means when you use the `java.io.PipedXxxStream', the writing data to it will eventually block unless you use two different threads.
So the answer from Apocalisp is correct: You must write a copy loop.
I suggest that you include Apache's commons-io in your project which contains many helper routines just for tasks like this (copy data between streams, files, strings and all combinations thereof).
See http://ostermiller.org/utils/CircularBuffer.html
I had to implement a filter for slow connections to Servlets so basically I wrapped the servlet output stream into a QueueOutputStream which will add every byte (in small buffers), into a queue, and then output those small buffers to a 2nd output stream, so in a way this acts as input/output stream, IMHO this is better than JDK pipes which won't scale that well, basically there is too much context switching in the standard JDK implementation (per read/write), a blocking queue is just perfect for a single producer/consumer scenario:
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.*;
public class QueueOutputStream extends OutputStream
{
private static final int DEFAULT_BUFFER_SIZE=1024;
private static final byte[] END_SIGNAL=new byte[]{};
private final BlockingQueue<byte[]> queue=new LinkedBlockingDeque<>();
private final byte[] buffer;
private boolean closed=false;
private int count=0;
public QueueOutputStream()
{
this(DEFAULT_BUFFER_SIZE);
}
public QueueOutputStream(final int bufferSize)
{
if(bufferSize<=0){
throw new IllegalArgumentException("Buffer size <= 0");
}
this.buffer=new byte[bufferSize];
}
private synchronized void flushBuffer()
{
if(count>0){
final byte[] copy=new byte[count];
System.arraycopy(buffer,0,copy,0,count);
queue.offer(copy);
count=0;
}
}
#Override
public synchronized void write(final int b) throws IOException
{
if(closed){
throw new IllegalStateException("Stream is closed");
}
if(count>=buffer.length){
flushBuffer();
}
buffer[count++]=(byte)b;
}
#Override
public synchronized void write(final byte[] b, final int off, final int len) throws IOException
{
super.write(b,off,len);
}
#Override
public synchronized void close() throws IOException
{
flushBuffer();
queue.offer(END_SIGNAL);
closed=true;
}
public Future<Void> asyncSendToOutputStream(final ExecutorService executor, final OutputStream outputStream)
{
return executor.submit(
new Callable<Void>()
{
#Override
public Void call() throws Exception
{
try{
byte[] buffer=queue.take();
while(buffer!=END_SIGNAL){
outputStream.write(buffer);
buffer=queue.take();
}
outputStream.flush();
} catch(Exception e){
close();
throw e;
} finally{
outputStream.close();
}
return null;
}
}
);
}
Better to use Pipe or ArrayBlockingQueue, I recommend you not to use PipedInput/OutputStream as they have a bad practice even you can see in the link below that they have asked to be deprecated as it causes many issues.
https://bugs.openjdk.java.net/browse/JDK-8223048
For the BlockingQueue and Pipe here a simple example of that
Pipe:
Pipe pipe = Pipe.open();
Pipe.SinkChannel sinkChannel = pipe.sink();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
sinkChannel.write(buf);
}
Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
Reference: http://tutorials.jenkov.com/java-nio/pipe.html
BlockingQueue:
//Shared class used by threads
public class Buffer {
// ArrayBlockingQueue
private BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(1);
public void get() {
// retrieve from ArrayBlockingQueue
try {
System.out.println("Consumer received - " + blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void put(int data) {
try {
// putting in ArrayBlockingQueue
blockingQueue.put(data);
System.out.println("Producer produced - " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// Starting two threads
ExecutorService executorService = null;
try {
Buffer buffer = new Buffer();
executorService = Executors.newFixedThreadPool(2);
executorService.execute(new Producer(buffer));
executorService.execute(new Consumer(buffer));
} catch (Exception e) {
e.printStackTrace();
}finally {
if(executorService != null) {
executorService.shutdown();
}
}
}
public class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
#Override
public void run() {
while (true) {
try {
buffer.get();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Producer implements Runnable {
private Buffer buffer;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
#Override
public void run() {
while (true) {
Random random = new Random();
int data = random.nextInt(1000);
buffer.put(data);
}
}
}
Reference:
https://github.com/kishanjavatrainer/ArrayBlockingQueueDemo/tree/master/ArrayBlockingQueueDemo