I run in a eclipse plugin Job a process that performs long operations without much output.
I want to be able to cancel the Job if users request it, but with the implementation bellow, the Job is not stopping unless the process prints something to the output stream.
Process process = new ProcessBuilder(args).start();
Scanner scanner = new Scanner(
(new InputStreamReader(
process.getInputStream(), UTF_8_CHARSET)));
while (scanner.hasNext())
{
if (monitor.isCanceled() {
// user canceled the job, destroy the process to return
process.destroy();
break;
}
CONSOLE.getStream().println(scanner.nextLine());
}
try {
process.waitFor();
} catch (InterruptedException e) {
Activator.log(ERROR, e.getMessage(), e);
} finally {
process.destroyForcibly();
}
Do I have other options to handle the cancelling of the job and to stop the process faster instead of waiting for a new line feed?
You should put the code reading the process output stream in to a separate thread and in your main loop just wait for the process to end with a short timeout so you can check for canceled.
So the main code would be something like:
Process process = new ProcessBuilder(args).start();
// Read standard output
new StreamConsumer(process.getInputStream()).start();
// You should also always read stderr
new StreamConsumer(process.getErrorStream()).start();
// Wait for process to end and check for cancel
while (!process.waitFor(100, TimeUnit.MILLISECONDS) {
if (monitor.isCanceled() {
// user canceled the job, destroy the process to return
process.destroy();
break;
}
}
And StreamConsumer is something like:
public class StreamConsumer extends Thread
{
private final InputStream _input;
public StreamConsumer(final InputStream inputStream)
{
super();
_input = inputStream;
setDaemon(true);
}
#Override
public void run()
{
// TODO your code to read the stream
}
}
Instead of a Scanner use a BufferedReader which provides the ready method which is a non-blocking way of telling you if there is something to read instead of using Scanner's nextLine() which is blocking until something is actually read.
Small example implementation:
volatile static boolean stop = false;
public static void main(String[] args) throws InterruptedException
{
// Create a new thread that reads input from System.in
new Thread(() -> {
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
while (!stop)
{
try
{
// If there is something to read read it and print it
if (read.ready())
{
System.out.println(read.readLine());
}
}
catch (IOException e)
{
// Do some handling...
}
}
}).start();
// Wait 5 seconds then stop the thread by making the flag false.
Thread.sleep(5000);
stop = true;
}
Your flag is obviously provided with the Process. The take away is to use a non-blocking operation (a peek if there is actually something to print) instead of using a blocking operation.
In my case i didn't know how long the process is going. So a timeout was no option.
My alternative solution is to start a separate monitor thread that is watching the state of the IProgressMonitor. If the progress monitor is in the canceled state then the executing thread is interupted.
public static void startMonitorThread(IProgressMonitor monitor) {
final Thread runThread = Thread.currentThread();
new Thread("Monitor") {
#Override
public void run() {
while (runThread.isAlive() && !monitor.isCanceled()) {
try {
Thread.sleep(100);
} catch (InterruptedException exception) {
break;
}
}
if (runThread.isAlive()) {
runThread.interrupt();
}
};
}.start();
}
The next snippet shows a example how this can be used:
startMonitorThread(monitor);
final Process process = new ProcessBuilder("...").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
while (process.isAlive()) {
if (reader.ready()) {
final String line = reader.readLine();
// ... do something with line
} else {
Thread.sleep(10);
}
}
}
First i did the same mistake to use a scanner that is blocking (and the interuption didn't worked). Like the answer of Ben is mentioning it is better to use a BufferedReader and the non blocking ready() method to check if there is more to read.
Related
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
I'm using ProcessBuilder in Java to run a process. I want my program to wait for the Process until it output stream has a line that matches a given pattern, or until a time limit exceeds.
I use BufferedReader to read line by line from Process.getOutputStream while matching each line to the pattern. It worked fine when there is a match or the process terminated before any match. But when the process doesn't output anymore line after a give time limit, the BufferedReader.readLine() block and the thread reading from Process.getOutputStream never completes.
Here is my code.
private static Timer setTimeout(Runnable runnable, long timeoutMillis) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
runnable.run();
timer.cancel();
}
}, timeoutMillis);
return timer;
}
static CompletableFuture<Process> startProcessAndWaitForMatchedOutput(
ProcessBuilder processBuilder, String pattern, long waitForMillis) {
final CompletableFuture<Process> completableFuture = new CompletableFuture<>();
final Process process;
try {
process = processBuilder.start();
} catch (IOException ex) {
completableFuture.completeExceptionally(ex);
return completableFuture;
}
final Pattern compiledPattern = Pattern.compile(pattern);
final Timer timeoutTimer = setTimeout(() ->
completableFuture.completeExceptionally(new WaitForTimeExceededException()),
waitForMillis);
new Thread(() -> {
try (InputStream processOutputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(processOutputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line;
/* The thread is blocked here.
Indeed the code call this method always return because
my completableFuture always completes.
But the problem is there is a running thread
which is a waste of resource. */
while ((line = bufferedReader.readLine()) != null) {
if (compiledPattern.matcher(line).matches()) {
completableFuture.complete(process);
timeoutTimer.cancel();
return;
}
}
completableFuture.completeExceptionally(new OutputDidNotMatchException());
timeoutTimer.cancel();
} catch (IOException ex) {
completableFuture.completeExceptionally(ex);
timeoutTimer.cancel();
}
}).start();
return completableFuture;
}
Is my solution correct? If not, is there some libraries that solve my problem?
I am writing a Java client application(Basic Java Net package with TCP/IP). The client must take input from the system.in and at the same time must listen to any messages coming from server through socket inputstream.
Once an input from the system.in is received, the client will get that input, do some processing and send it to the server as a request.
So basically 2 processes run,
-listening to client request
-listning to server responses.
I implemented 2 threads for this and ran the processing of messages in the main thread.
Is this good enough design.?
And is there a way to return the message received from the system.in to the main thread. The threads run() method returns void. I used a volatile variable to return the string received but its said that volatile is very costly since it doesn't use cpu cache to store the variable.
You can review these two projects I've written for an example of java sockets and multithreading.
Client
Server
I guess the ClientExample is the one you are searcing for but you can take a look at the server part too.
Basically the idea is to start two separate threads that listen for the different inputs - socket and console.
final Thread outThread = new Thread() {
#Override
public void run() {
System.out.println("Started...");
PrintWriter out = null;
Scanner sysIn = new Scanner(System.in);
try {
out = new PrintWriter(socket.getOutputStream());
out.println(name);
out.flush();
while (sysIn.hasNext() && !isFinished.get()) {
String line = sysIn.nextLine();
if ("exit".equals(line)) {
synchronized (isFinished) {
isFinished.set(true);
}
}
out.println(line);
out.flush();
disconnect();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
};
};
outThread.start();
and another thread for the socket input:
final Thread inThread = new Thread() {
#Override
public void run() {
// Use a Scanner to read from the remote server
Scanner in = null;
try {
in = new Scanner(socket.getInputStream());
String line = in.nextLine();
while (!isFinished.get()) {
System.out.println(line);
line = in.nextLine();
}
} catch (Exception e) {
// e.printStackTrace();
} finally {
if (in != null) {
in.close();
}
}
};
};
inThread.start();
I hope this will help you :)
I'm trying to use server sockets to set up a connection between a client and a server. I'm also not using java.nio.
The problem is that I'm constantly sending a test message, and detecting whether if it is successful in sending the message (the client is still connected), if not, then the client is disconnected.
Shown here:
try
{
Scanner in = new Scanner(socket.getInputStream());
BufferedReader in_2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(stopThread)
{
if(in_2.ready())
{
String message = in_2.readLine();
dt = new DateTime();
PrintStream out = new PrintStream(socket.getOutputStream());
server.detect(message, dataSets, out);
dataSets.add(message);
GUI.textArea_1.append(message + "\r\n");
GUI.textArea_1.setCaretPosition(GUI.textArea_1.getDocument().getLength());
}
else
{
PrintStream out = new PrintStream(socket.getOutputStream());
out.println("Testing Connection \r\n");
if(out.checkError())
{
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
stopThread = false;
GUI.textArea.append(userName + " disconnected \r\n");
GUI.textArea.setCaretPosition(GUI.textArea.getDocument().getLength());
server.inputDataForm(userName, dt, dataSets);
}
Thread.sleep(3000);
}
}
The problem is that the Thread.sleep(3000) is actually interfering with getting data, since after 3 seconds, I will get a huge amount of data (because I stopped the thread for 3 seconds).
Now, what I proposed is a anonymous class in the else statement.
class runThread implements runnable
{
void run()
{
//Put the else statement here
}
}
But the stopThread = false is not a constant, which I'm trying to control.
Other threads I've searched only puts variables inside main inside the anonymous class, but I need stopThread to stop the while loop if the client is disconnected.
Does anyone have an idea?
Thanks!
Consider setting a short timeout on your socket. This will allow you to control how long your thread will block while waiting for data from the socket.
If data are not quickly available, a very specific java.net.SocketTimeoutException will be raised. You can handle this exception by checking your stopThread flag. If it is set, you can return from the method. Otherwise, the socket is still valid and you can try another read operation with timeout.
If any other exception type is thrown, your socket is probably no longer valid.
socket.setSoTimeout(20); /* 1/50th of a second. */
BufferedReader in = new BufferedReader
(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
while (!stop) {
try {
String message = in.readLine();
if (message == null)
handleEOF();
else
handleMessage(message);
} catch(SocketTimeoutException ignore) {
/* Loop back to check "stop" flag. */
continue;
} catch(IOException ex) {
handleDisconnection();
break;
}
}
By the way, if you are using Swing, remember that you can only modify graphical components from Swing's Event Dispatch Thread, and you can't tie up the EDT in long-running operations like this socket handling. You should be passing tasks from this thread to Swing's invokeLater() utility.
Why don't you make a class that implements runnable but also has the method stop();
public class MyRunner implements Runnable(){
MutableBoolean stop = false;
public void run(){...}
public void stop(){
stop = true;
}
}
I am writing a Java client/server GUI application using sockets and here is the problem:
I have a button to start listening for a specified port:
button actionPerformed method
private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {
int port = Integer.parseInt(portTextfield.getText(), 10);
try {
socket.listen(port);
} catch (IOException ex) {
}
}
Here is the socket.listen method
public static void listen() throws IOException {
ServerSocket ss = new ServerSocket(port);
while (true)
new socket(ss.accept());
}
"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.
After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?
You have two pitfalls in your design:
ss.accept() is a blocking call so your UI will freeze until there is an incoming connection
Never run while(true) loops in the EDT.
Instead do the following:
When the button is clicked create a thread that will start listening for incoming connections.
Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
as long as your
new socket(ss.accept());
returns immediately, you only need to change your
while (true)
this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.
If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List)
Create a nested class that extents SwingWorker. Just call a swingWoker.execute(); (after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt) method.
See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Never create a new thread and run it from from the Swing EDT
Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html
1) If you are writing GUI application may be in Swing never call
blocking method in Event dispatcher thread or in the event handler.
for example if you are reading a file or opening a network connection
when a button is clicked don't do that on actionPerformed() method,
instead just create another worker thread to do that job and return
from actionPerformed(). this will keep your GUI responsive, but again
it depends upon design if the operation is something which requires
user to wait than consider using invokeAndWait() for synchronous
update.
Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html
You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.
Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.
Try these...
1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.
`Socket s = new Socket();`
`s.connect(new InetSocketAddress("ip_addr",port_nos),1000);`
2. And Secondly always keep the Non-UI work out of Your UI thread..
Here is my Example of Server - Client Communication..
Client side code:
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket();
s.connect(new InetSocketAddress("127.0.0.1", 4444),1000);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server side code:
import java.io.*
import java.net.*;
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}