How do I ensure that:
1.) localThread and remoteThread run independent of each other?
2.) pass messages between localThread and remoteThread?
Specifically, a String object from localThread needs to "percolate" up to Telnet through, I think it's known as, a call-back. However, there's not really anything, per se, for Telnet to observe. It's an anonymous reference to LocalIO, and I don't see that explicitly providing a reference helps.
I've read about java.util.concurrent.Semaphore until my head exploded, all I came away with was that it doesn't seem to apply. For these two threads, they should continue to run regardless of what the other thread is doing. However, there needs to be some mechanism to pass object references between the threads...
public class Telnet {
public Telnet() throws InterruptedException {
startThreads();
}
public static void main(String[] args) throws InterruptedException {
new Telnet();
}
public void startThreads() throws InterruptedException {
Semaphore s = new Semaphore(1, true);
Thread localThread = new Thread(new LocalIO());
Thread remoteThread = new Thread(new RemoteIO());
localThread.start();
remoteThread.start();
}
}
The threads themselves are as follows. LocalIO:
public class LocalIO implements Runnable {
#Override
public void run() {
Scanner scanner;
String line;
while (true) {
scanner = new Scanner(System.in);
line = scanner.nextLine();
out.println("\n\nyou entered\t\"" + line + "\"\n");
}
}
}
RemoteIO:
public class RemoteIO implements Runnable {
private static Logger log = Logger.getLogger(RemoteIO.class.getName());
final String host = "rainmaker.wunderground.com";
final int port = 3000;
#Override
public void run() {
log.fine(host + port);
int byteOfData;
try (Socket socket = new Socket(host, port);
InputStream inputStream = socket.getInputStream();
OutputStream ouputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
while ((byteOfData = inputStream.read()) != -1) {
out.print((char) byteOfData);
}
} catch (Exception e) {
out.println(e);
}
}
}
Keeping in mind that RemoteIO never closes its connection and runs indefinitely.
The concurrent package is very helpful for this sort of thing:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html
For example you can just give each thread a ConcurrentLinkedQueue and they can check the queue to see if there is anything to act on whenever they please. Meanwhile other threads can add new objects to the queue whenever they please.
There is one essential difference in the programming paradigm your code can adopt:
synchronous mode: the receiving end runs an endless loop which explicitly takes items off a concurrent queue, blocking when there are no items ready;
asynchronous mode: the receiving end submits a callback to an item exchange mechanism. This callback is called for every item which arrives from the producer thread.
The Observer pattern may loosely apply to the latter case, but not to the former.
Also note that in the latter case, the "item exchange mechanism" is usually implemented in the synchronous mode.
Not sure what yu are trying to do, but if you want to exchange data between threads, you need a volatile variable to make sure changes are seen by other threads. AtomicReferences are non-blocking and provide some API that might help here.
The solution I found:
public class RemoteConnection extends Observable {
private static Logger log = Logger.getLogger(RemoteConnection.class.getName());
private final Socket socket;
private final BufferedInputStream in;
private final BufferedOutputStream out;
private final static String UTF8 = "UTF-8";
public RemoteConnection(String host, int port) throws UnknownHostException, IOException {
socket = new Socket(host, port);
in = new BufferedInputStream(socket.getInputStream());
out = new BufferedOutputStream(socket.getOutputStream());
}
public void write(Deque<String> commands) throws IOException {
String command;
while (!commands.isEmpty()) {
command = commands.pop();
out.write(command.concat("\r\n").getBytes(Charset.forName(UTF8)));
log.info(command);
}
out.flush();
}
void read() { //probably should use BufferedStream to better effect..?
Thread readRemote = new Thread() {
#Override
public void run() {
StringBuilder sb = new StringBuilder();
char ch;
int i;
while (true) {
try {
i = in.read();
ch = (char) i;
sb.append(ch);
System.out.print(ch);
if (i == 13) {
setChanged();
notifyObservers(sb.toString());
log.fine(sb.toString());
sb = new StringBuilder();
}
} catch (IOException ioe) {
log.fine(ioe.toString());
}
}
}
};
readRemote.start();
}
}
By reorganizing the threading, this approximates a poor-mans telnet, with asynchronous threads for i/o. I think reading from the console was blocking...something...
I really don't know why this works but the other approaches didn't. I would've preferred to have the main class start and handle threads, and pass references between the threads, but that just didn't work despite using the various solutions offered here.
LocalConnection has a similar threading approach.
Related
I am working on a simple project: Server executes a slave (ReaderF Class) inside a thread that reads a file and then extracts its content and saves it inside the Server himself. The server then needs to execute a pool to send the content to a client when he connects. I started by writing the ReaderF to extract the content. Problem: it never edits the String variable in which he is supposed to stock the content. Here is what I did:
public class Serveur {
private ServerSocket serverSocket;
private Socket socket;
public String res=null; //This is what my thread is supposed to be editing
ExecutorService pool = null;
public static final int port = 33333;
Serveur(int port, int size){
try {
pool = Executors.newFixedThreadPool(5);
serverSocket = new ServerSocket(port, size);
} catch (IOException ex) {
Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE, null, ex);
}
}
void manage () throws IOException {
while(true) {
ReaderF S = null;
try {
S = new ReaderF(serverSocket.accept(), this);
} catch (IOException e) {
e.printStackTrace();
}
Thread t=new Thread(S);
t.start();
}
}
And this is the slave that reads and edit the res variable.
public class ReaderF implements Runnable {
private final Socket socket;
private Serveur serverMaitre;
ReaderF(Socket socket, Serveur serverMaitre) {
this.socket = socket;
this.serverMaitre = serverMaitre;
}
public void run() {
String fileName = "/home/abdou/1.txt";
FileReader fileReader = null;
Writer output =null;
try {
fileReader = new FileReader(fileName);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
output = new OutputStreamWriter(socket.getOutputStream(), "8859_1");
String line;
String res="";
while((line = bufferedReader.readLine()) != null) {
res+=line+"\n";
}
serverMaitre.res=res; // This is where i tell him to edit res inside the server
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
When I execute this main I see nothing on the screen. I know that it is due to the fact that the Server is stuck in the while loop.
public class Main{
public static void main(String[] args) throws IOException {
Serveur serveur = new Serveur(Serveur.port, 1);
serveur.manage();
System.out.println("The res variable content is"+serveur.res);
}}
How would I get out of it please. And Is my thread really changing the res variable ? Thank you
When multiple threads work with the same variables, then they are allowed to work on a local copy of the variable (in their stack) instead of the original variable (in the heap). This means that one thread may not see changes to a variable that another thread did (he is not 'refreshing' its local data), or the other thread is not 'publishing' (technical term: flushing) the updated value. So, when your ReaderF assign a value to 'res', the main thread (which is checking it) might not notice this. Solution: Make the variable volatile:
public volatile String res=null;
This forces the ReaderF to flush the updated value after assigning, and the main thread to refresh it when reading it.
But you might have another problem here, because you have multiple threads that may be all writing the 'res' variable (Depends on how active your socket is). You can get 'lost updates' or other 'race conditions' here. So maybe you even need a synchronized somewhere. But it would be too much to explain Multi-Threading here. Please google about it. Multi-Threading is not trivial unfortunately, you cannot just make new threads as you wish and expect everything to work. And adding a volatile is not the solution most of the time. It might just be enough for what you wanna do here.
I am working on a project and for one part of my project I have as ArrayList of Strings I keep on record to hold onto incoming messages from other systems that are interconnected. This is a peer to peer design so I wanna have a BufferedReader ready to read any messages sent from any sockets to the system, so I designed a thread that, when created, creates a new thread for each socket that will listen to a specific input stream.
Right now I have attempted this using the following two private classes:
InputListener(inner class ListenerThread)
private class InputListener implements Runnable{
private ArrayList<String> queue;
private ArrayList<Stream> sockets;
private ArrayList<Thread> threads;
public InputListener(ArrayList<String> q, ArrayList<Stream> s)
{
this.queue = q;
this.sockets = s;
this.threads = new ArrayList<Thread>();
for(int i = 0; i < this.sockets.size(); i++)
{
Thread t = new Thread(new ListeningThread(this.sockets.get(i).is, this.queue));
t.start();
threads.add(t);
}
}
private class ListeningThread implements Runnable{
private BufferedReader read;
private ArrayList<String> queue;
private boolean status;
public ListeningThread(InputStream is, ArrayList<String> q)
{
this.read = new BufferedReader(new InputStreamReader(is));
this.queue = q;
status = true;
}
#Override
public void run() {
while(true)
{
String str = "";
try {
str += read.readLine();
while(!str.equals("END"))
str += read.readLine();
this.queue.add(str);
} catch (IOException e) {
status = false;
break;
}
}
}
}
#Override
public void run() {
while(status)
;
}
}
Stream
private class Stream{
public InputStream is;
public OutputStream os;
public Stream(final Socket s)
{
try {
this.is = s.getInputStream();
this.os = s.getOutputStream();
} catch (IOException e) {
return;
}
}
public InputStreamReader getReader()
{
return new InputStreamReader(this.is);
}
}
When I create the InputListener I pass a reference to a queue from another class, I am excluding this class to prevent over complicating this problem, so assume that this ArrayList is initialized and it's pointer(I cant remember what java calls it) is passed. My problem is that when I use a loop like the following, I just get trapped in an infinite loop
while(queue.size equals 0)
Do nothing
Remove and do something with String at index 0 in queue
Can anyone help me with this problem? any help will be greatly appriciated!
You should use one of the specialized container classes in java.util.concurrent instead of a standard unsynchronized ArrayList.
For example, LinkedBlockingQueue.
// in the setup
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// in producer thread
queue.put(work);
// in consumer thread
work = queue.take(); // blocking - waits as long as needed
I also suggest reading the Java Tutorial on Concurrency. It is not a trivial subject.
I am using this code in a application for sending some string throw a socket.
public class OutgoingData {
public static DataOutputStream dos = null;
public static String toSend = "";
public static volatile boolean continuousSending = true;
public static String toSendTemp = "";
public static void startSending(final DataOutputStream d) {
new Thread(new Runnable() {
public void run() {
try {
dos = d;
while (continuousSending) {
if (!toSend.equals(toSendTemp)) {
dos.writeUTF(toSend);
dos.flush();
toSendTemp = toSend;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
And from another thread I am calling this method
private void send(String str) {
OutgoingData.toSend = str;
}
Are there any problems that could appear using this implementation? Excepting the case when send() is called synchronously from two threads.
I am not using something like this:
private void send(final String str){
new Thread(new Runnable() {
#Override
public void run() {
synchronized (OutgoingData.dos) {
try {
OutgoingData.dos.writeUTF(str);
OutgoingData.dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
Because the system on which this code is runned, has a limit on the number of threads a process can create and takes a long time to get a lock on an object.
Your implementation is not thread safe:
if (!toSend.equals(toSendTemp)) {
// toSend can be changed before this line happens
// causing you to miss data
dos.writeUTF(toSend);
dos.flush();
// or here
toSendTemp = toSend;
}
You need some form of thread synchronization, regardless of whether or not it is "slow".
A better choice rather than busy waiting on a field is to use a BlockingQueue<String> This will ensure you never miss a value, nor do you consume CPU when there is nothing to do.
A good way of wrapping up a Queue and a Thread (pool) is to use an ExecutorService which does both.
In your case, a Socket stream is a queue already so queuing writing to another queue is likely to be redundant and all you really need to buffer your output stream.
Because the system on which this code is runned, has a limit on the number of threads a process can create and takes a long time to get a lock on an object.
Creating a thread is more than 100x than creating a thread. Ideally you don't want to have either. Note: the Socket already has a write lock.
I am new to multithreading & socket programming in Java. I would like to know what is the best way to implement 2 threads - one for receiving a socket and one for sending a socket. If what I am trying to do sounds absurd, pls let me know why! The code is largely inspired from Sun's tutorials online.I want to use Multicast sockets so that I can work with a multicast group.
class Server extends Thread
{
static protected MulticastSocket socket = null;
protected BufferedReader in = null;
public InetAddress group;
private static class Receive implements Runnable
{
public void run()
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
socket.receive(pkt);
String received = new String(pkt.getData(),0,pkt.getLength());
System.out.println("From server#" + received);
Thread.sleep(1000);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
}
public Server() throws IOException
{
super("server");
socket = new MulticastSocket(4446);
group = InetAddress.getByName("239.231.12.3");
socket.joinGroup(group);
}
public void run()
{
while(1>0)
{
try
{
byte[] buf = new byte[256];
DatagramPacket pkt = new DatagramPacket(buf,buf.length);
//String msg = reader.readLine();
String pid = ManagementFactory.getRuntimeMXBean().getName();
buf = pid.getBytes();
pkt = new DatagramPacket(buf,buf.length,group,4446);
socket.send(pkt);
Thread t = new Thread(new Receive());
t.start();
while(t.isAlive())
{
t.join(1000);
}
sleep(1);
}
catch (IOException e)
{
System.out.println("Error:"+e);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
}
//socket.close();
}
public static void main(String[] args) throws IOException
{
new Server().start();
//System.out.println("Hello");
}
}
First thing is first: your classes should start with a capital letter per the Java Naming Conventions:
Class names should be nouns, in mixed case with the first letter of
each internal word capitalized. Try to
keep your class names simple and
descriptive. Use whole words-avoid
acronyms and abbreviations (unless the
abbreviation is much more widely used
than the long form, such as URL or
HTML).
Second:
Try to break down the code into coherent sections and organize them around some common feature that you're dealing with... perhaps around the functionality or the model you're programming.
The (basic) model for the server is that the only thing it does is receive socket connections... the server relies on a handler to handle those connections and that's it. If you try to build that model it would look something like this:
class Server{
private final ServerSocket serverSocket;
private final ExecutorService pool;
public Server(int port, int poolSize) throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void serve() {
try {
while(true) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// receive the datagram packets
}
}
Third: I would recommend that you look at some existing examples.
Multi-threaded Client/Server Applications:
http://www.ase.md/~aursu/ClientServerThreads.html
Doug Lea:
http://www.developer.com/java/ent/article.php/3645111/Java-5s-BlockingQueue.htm (thanks to John)
http://gee.cs.oswego.edu/dl/cpj/index.html (still can't find the exact example, but it's there somewhere... if you feel brave look over his allcode.java file).
Concurrency in Practice examples:
http://www.javaconcurrencyinpractice.com/listings.html
Java Concurrency Tutorials:
http://java.sun.com/docs/books/tutorial/essential/concurrency/
Updated per comments:
OK Ravi, there are some big issues with your code and some minor issues with it:
I assume that the Receive class is your client... you should pull that out as a separate program (with its own main class) and run your server and multiple clients at the same time. Spawning a new "client thread" from your server for every new UDP package you send is a disturbing idea (big issue).
When you make your client application, you should make it run the receiving code in its own while loop (minor issue), e.g.:
public class Client extends Thread
{
public Client(/*..*/)
{
// initialize your client
}
public void run()
{
while(true)
{
// receive UDP packets
// process the UDP packets
}
}
public static void main(String[] args) throws IOException
{
// start your client
new Client().start();
}
}
You should only need just one thread per client and one thread per server (you technically don't even a separate thread in there since main has its own thread), so you might not find the ExecutorService that useful.
Otherwise your approach is correct... but I would still recommend that you check out some of examples.
Wanting to create threads in an application is not absurd! You won't need exactly 2 threads, but I think you're talking about 2 classes that implement the Runnable interface.
The threading API has gotten better since Java 1.5 and you don't need to mess with java.lang.Thread anymore. You can simply create a java.util.concurrent.Executor and submit Runnable instances to it.
The book Java Concurrency in Practice uses that exact problem - creating a threaded socket server - and walks through several iterations of the code to show the best way to do it. Check out the free sample chapter, which is great. I won't copy/paste the code here, but look specifically at listing 6.8.
It's a good thing Eclipse's history works even for a day back :) Thanks to that, I am able to give both Ravi a working example and Lirik his answer on leakage.
Let me first start of by stating that I have no clue what is causing this leak, but if I leave it long enough, it will fail on a OutOfMemoryError.
Second, I left the working code commented out for Ravi for a working basic example of my UDP server. The timeout was there to test how long my firewall would kill the receivers end (30 seconds). Just remove anything with the pool, and you're good to go.
So here is, a working but leaking version of my example threaded UDP server.
public class TestServer {
private static Integer TIMEOUT = 30;
private final static int MAX_BUFFER_SIZE = 8192;
private final static int MAX_LISTENER_THREADS = 5;
private final static SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSSZ");
private int mPort;
private DatagramSocket mSocket;
// You can remove this for a working version
private ExecutorService mPool;
public TestServer(int port) {
mPort = port;
try {
mSocket = new DatagramSocket(mPort);
mSocket.setReceiveBufferSize(MAX_BUFFER_SIZE);
mSocket.setSendBufferSize(MAX_BUFFER_SIZE);
mSocket.setSoTimeout(0);
// You can uncomment this for a working version
//for (int i = 0; i < MAX_LISTENER_THREADS; i++) {
// new Thread(new Listener(mSocket)).start();
//}
// You can remove this for a working version
mPool = Executors.newFixedThreadPool(MAX_LISTENER_THREADS);
} catch (IOException e) {
e.printStackTrace();
}
}
// You can remove this for a working version
public void start() {
try {
try {
while (true) {
mPool.execute(new Listener(mSocket));
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
mPool.shutdown();
}
}
private class Listener implements Runnable {
private final DatagramSocket socket;
public Listener(DatagramSocket serverSocket) {
socket = serverSocket;
}
private String readLn(DatagramPacket packet) throws IOException {
socket.receive(packet);
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(packet.getData())), MAX_BUFFER_SIZE).readLine();
}
private void writeLn(DatagramPacket packet, String string) throws IOException {
packet.setData(string.concat("\r\n").getBytes());
socket.send(packet);
}
#Override
public void run() {
DatagramPacket packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
String s;
while (true) {
try {
packet = new DatagramPacket(new byte[MAX_BUFFER_SIZE], MAX_BUFFER_SIZE);
s = readLn(packet);
System.out.println(DateFormat.format(new Date()) + " Received: " + s);
Thread.sleep(TIMEOUT * 1000);
writeLn(packet, s);
System.out.println(DateFormat.format(new Date()) + " Sent: " + s);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
if (args.length == 1) {
try {
TIMEOUT = Integer.parseInt(args[0]);
} catch (Exception e) {
TIMEOUT = 30;
}
}
System.out.println(DateFormat.format(new Date()) + " Timeout: " + TIMEOUT);
//new TestServer(4444);
new TestServer(4444).start();
}
}
btw. #Lirik, I witnessed this behavior first in Eclipse, after which I tested it from the command line. And again, I have NO clue what is causing it ;) sorry...
2 threads is fine. One reader another writer. Remember that with UDP you should not spawn new handler threads (unless what you're doing takes a long time), I recommend throwing the incoming messages into a processing Queue. The same for the send, have a send thread that blocks on an incoming Queue for UDP send.
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