I have a Java application which launches another application with some parameters. The Java should be able to continue meanwhile and kill the other application after user input.
Reading up on this I found out I should use Thread.Interupt() because Thread.Stop() is deprecated.
On your thread it would throw a InterruptedExection. So what I have is:
public class ProcessExecutor extends Object implements Runnable {
private volatile int id;
private String message;
private Process proc = null;
public ProcessExecutor(int id, String message) {
this.id = id;
this.message = message;
}
public int GetId() {
return id;
}
public void run() {
try {
String[] cmd = new String[4];
cmd[0] = "path to some app";
cmd[1] = id;
cmd[2] = message;
Runtime rt = Runtime.getRuntime();
proc = rt.exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line=null;
while ((line=input.readLine()) != null) {
System.out.println("ProcessExecutor: " + line);
}
int exitVal = proc.waitFor();
System.out.println("ProcessExecutor: Exited with error code " + exitVal);
} catch(InterruptedException ex) {
System.out.println("ProcessExecutor: stopping");
if (proc != null) {
proc.destroy();
proc = null;
}
} catch(Exception e) {
System.out.println("ProcessExecutor: exception: " + e.toString());
e.printStackTrace();
}
}
}
Which is handled by:
private List<Thread> activeProccesses = new ArrayList<Thread>();
public void StartProcess(int id, String message) {
System.out.println("StartProcess: id=" + id + ", message='" + message + "'");
StopAllProcesses();
ProcessExecutor proc = new ProcessExecutor(id, message);
Thread procThread = new Thread(proc);
activeProccesses.add(procThread);
procThread.start();
}
public void StopAllProcesses() {
System.out.println("Stopping all processes");
Iterator<Thread> it = activeProccesses.iterator();
while (it.hasNext()) {
Thread procThread = it.next();
if (procThread.isAlive()) {
procThread.interrupt();
}
it.remove();
}
System.out.println("Stopping all processes: done");
}
How ever the procThread.interrupt() gets executed but the catch(InterruptedException ex) never hits.
Why is this and how can I fix this?
Edit: The conclusion
Turned out the Thread was blocked by the input.readLine() inorder to stop that I had to directly stop the Process which then unblocked the input.readLine().
public class ProcessExecutor extends Thread {
private volatile int id;
private String message;
private volatile Process proc = null;
public ProcessExecutor(int id, String message) {
this.id = id;
this.message = message;
}
public int GetId() {
return id;
}
public void StopProc() {
if (proc != null) {
proc.destroy();
}
}
public void run() {
try {
String[] cmd = new String[4];
cmd[0] = "path to some app";
cmd[1] = id;
cmd[2] = message;
Runtime rt = Runtime.getRuntime();
proc = rt.exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line=null;
while ((line=input.readLine()) != null) {
System.out.println("ProcessExecutor: " + line);
}
int exitVal = proc.waitFor();
proc = null;
System.out.println("ProcessExecutor: Exited with error code " + exitVal);
} catch(Exception e) {
System.out.println("ProcessExecutor: exception: " + e.toString());
StopProc();
}
}
}
private List<ProcessExecutor> activeProccesses = new ArrayList<ProcessExecutor>();
public void StartProcess(int id, String message) {
System.out.println("StartProcess: id=" + id + ", message='" + message + "'");
StopAllProcesses();
ProcessExecutor proc = new ProcessExecutor(id, message);
activeProccesses.add(proc);
proc.start();
}
public void StopAllProcesses() {
System.out.println("Stopping all processes");
Iterator<ProcessExecutor> it = activeProccesses.iterator();
while (it.hasNext()) {
ProcessExecutor proc = it.next();
proc.StopProc();
it.remove();
}
System.out.println("Stopping all processes: done");
}
As I said in my comment. I think the only way to interrupt a thread blocked reading a line is to kill the process from which the thread reads. Just as the only solution to interrupt a thread blocked reading on a socket is to close the socket.
Add a method to your thread that destroys the process.
You have to explicitly check for the interrupted condition in your ProcessExecutor; an InterruptedException will not be thrown automatically. Something like this:
public class ProcessExecutor extends Object implements Runnable {
public void run() {
try {
//other code....
while ((line=input.readLine()) != null) {
System.out.println("ProcessExecutor: " + line);
if (Thread.interrupted()) {
// We've been interrupted!
throw new InterruptedException("....");
}
}
} catch(InterruptedException ex) {
System.out.println("ProcessExecutor: stopping");
}
See http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html for more details.
Interrupting threads only works if they are in specific states, usually it's done during wait() calls that are done when not actively processing data.
If you want the thread to die in between readLine() calls you can check interrupted() in the while check instead of using a try-catch.
Edit: the best way to solve your problem would be
while (true)
{
if (input.ready())
{
line = input.readLine();
System.out.println("ProcessExecutor: " + line);
} else {
try { Thread.sleep(100); } // time to wait in ms
catch (InterruptedException ie) { break; }
}
}
Since ready() actually checks for a single character you should use successive read() instead of readLine(), but if you write on the stream a line at a time there should be no difference this way. The time to wait for is clearly arbitrary.
I would suggest more graceful way to stop a thread. In the run method, you have following code
while ((line=input.readLine()) != null) {
System.out.println("ProcessExecutor: " + line);
}
in ProcessExecutor, add a boolean field accompanied by its getter and setter.
private Boolean stop = false;
and check the same flag in while condition.
while (((line=input.readLine()) != null) && !stop) {
System.out.println("ProcessExecutor: " + line);
}
in StopAllProcesses() method, set stop=true on ProcessExecutor instances . this will result into run() method returning and gracefully stopping the thread.
Related
I am writing simple Java Server which connecting only 5 users and run simply game.
My problem is communicate with clients, because the Game object is in Main Thread and every single subthread get information about specific player move (1-5 id). I don't know how to send this information to Main Thread and update game status.
Is my code correct, there aren't exists any big mistakes (this is my first project with multitasking), and what i supposed to do to communicate with Main Thread
Player.java
package Model;
import java.io.*;
import java.net.Socket;
public class Player extends Thread{
private long id;
private Socket clientSocket;
private InputStream clientInput;
private BufferedReader clientIn;
private DataOutputStream clientOut;
private String nickname;
private boolean isReady;
public Player(long id, Socket clientSocket) throws IOException {
this.id = id;
this.clientSocket = clientSocket;
this.clientInput = this.clientSocket.getInputStream();
this.clientIn = new BufferedReader(new InputStreamReader(this.clientInput));
this.clientOut = new DataOutputStream(this.clientSocket.getOutputStream());
this.isReady = false;
clientOut.writeBytes("POLACZONO\n");
clientOut.flush();
}
public void run() {
boolean isCorrect = false;
try {
while(!isCorrect) {
String login = this.clientIn.readLine();
if (!login.equals("") && login.startsWith("LOGIN") && login.length() > 6) {
this.clientOut.writeBytes("OK\n");
this.clientOut.flush();
setNickname(login.substring(login.indexOf(" ") + 1));
isCorrect = true;
this.isReady = true;
} else if (!login.equals("") && (!login.startsWith("LOGIN") || login.length() <= 6)) {
this.clientOut.writeBytes("ERROR\n");
this.clientOut.flush();
}
}
while (true) {
//DATA FROM CLIENT
}
//this.clientOut.writeBytes("START " + this.id + " " + startPlayer + "\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
this.clientSocket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Main Thread
public void startServer(ServerSocket serverSocket) throws IOException {
playerList = Collections.synchronizedList(new ArrayList<Player>());
int remaining = 1;
while (true) {
if(playerList.size() < 5) {
while (playerList.size() < 5) {
Socket connectionSocket = serverSocket.accept();
playerList.add(new Player(remaining, connectionSocket));
playerList.get(playerList.size() - 1).start();
remaining++;
}
}
final int startPlayer;
if(!playerList.stream().noneMatch(x -> x.isReady())) {
startPlayer = new Random().nextInt((5 - 1) + 1) + 1;
for (Player player : playerList) {
player.getClientOut().writeBytes("START " + player.getId() + " " + startPlayer + "\n");
}
//GAME START
}
}
}
Ok it means you used one thread per user for read data and just one thread to send data to users !
In main thread you can use a LinkedBlockingQueue and pass this queue to reader threads ! Each time a packet received you can put it to the queue and take it in main thread !
Soyou must write this in your reader thread :
queue.put(data);
And this in main thread :
data = queue.take();
This queue is thread safe , so it means multi thread can put and take data !
The take method will block thread until a data put to the queue.
I am trying to give a pop up alert message when my ThreadpoolExecutor is finished executing. It is searching email addresses from websites, once it is done I want a alert message as "Completed". Here is my Thread :-
public class Constant
{
public static final int NUM_OF_THREAD = 60;
public static final int TIME_OUT = 10000;
}
ThreadPoolExecutor poolMainExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool
(Constant.NUM_OF_THREAD);
Here is my Searching Operation class :-
class SearchingOperation implements Runnable {
URL urldata;
int i;
Set<String> emailAddresses;
int level;
SearchingOperation(URL urldata, int i, Set<String> emailAddresses, int level) {
this.urldata = urldata;
this.i = i;
this.emailAddresses = emailAddresses;
this.level = level;
if (level != 1)
model.setValueAt(urldata.getProtocol() + "://" + urldata.getHost() + "/contacts", i, 3);
}
public void run() {
BufferedReader bufferreader1 = null;
InputStreamReader emailReader = null;
System.out.println(this.i + ":" + poolMainExecutor.getActiveCount() + ":" + level + ";" + urldata.toString());
try {
if (level < 1) {
String httpPatternString = "https?:\\/\\/(www\\.)?[-a-zA-Z0-9#:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9#:%_\\+.~#?&//=]*)";
String httpString = "";
BufferedReader bufferreaderHTTP = null;
InputStreamReader httpReader = null;
try {
httpReader = new InputStreamReader(urldata.openStream());
bufferreaderHTTP = new BufferedReader(httpReader
);
StringBuilder rawhttp = new StringBuilder();
while ((httpString = bufferreaderHTTP.readLine()) != null) {
rawhttp.append(httpString);
}
if (rawhttp.toString().isEmpty()) {
return;
}
List<String> urls = getURL(rawhttp.toString());
for (String url : urls) {
String fullUrl = getMatchRegex(url, httpPatternString);
if (fullUrl.isEmpty()) {
if (!url.startsWith("/")) {
url = "/" + url;
}
String address = urldata.getProtocol() + "://" + urldata.getHost() + url;
fullUrl = getMatchRegex(address, httpPatternString);
}
if (!addressWorked.contains(fullUrl) && fullUrl.contains(urldata.getHost())) {
addressWorked.add(fullUrl);
sendToSearch(fullUrl);
}
}
} catch (Exception e) {
//System.out.println("652" + e.getMessage());
//e.printStackTrace();
return;
} finally {
try {
if (httpReader != null)
bufferreaderHTTP.close();
} catch (Exception e) {
// e.printStackTrace();
}
try {
if (httpReader != null)
httpReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
String someString = "";
emailReader = new InputStreamReader(urldata.openStream());
bufferreader1 = new BufferedReader(
emailReader);
StringBuilder emailRaw = new StringBuilder();
while ((someString = bufferreader1.readLine()) != null) {
if (someString.contains("#")) {
emailRaw.append(someString).append(";");
}
}
//Set<String> emailAddresses = new HashSet<String>();
String emailAddress;
//Pattern pattern = Pattern
//.compile("\\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\\.[a-zA-Z0-9.-]+\\b");
Pattern
pattern = Pattern
.compile("\\b[a-zA-Z0-9.-]+#[a-zA-Z0-9.-]+\\.[a-zA-Z0-9.-]+\\b");
Matcher matchs = pattern.matcher(emailRaw);
while (matchs.find()) {
emailAddress = (emailRaw.substring(matchs.start(),
matchs.end()));
// //System.out.println(emailAddress);
if (!emailAddresses.contains(emailAddress)) {
emailAddresses.add(emailAddress);
// //System.out.println(emailAddress);
if (!foundItem.get(i)) {
table.setValueAt("Found", i, 4);
foundItem.set(i, true);
}
String emails = !emailAddresses.isEmpty() ? emailAddresses.toString() : "";
model.setValueAt(emails, i, 2);
model.setValueAt("", i, 3);
}
}
} catch (Exception e) {
//System.out.println("687" + e.getMessage());
} finally {
try {
if (bufferreader1 != null)
bufferreader1.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (emailReader != null)
emailReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Thread.currentThread().interrupt();
return;
}
}
After this the final snippet :-
private void sendToSearch(String address) throws Throwable {
SearchingOperation operation = new SearchingOperation(new URL(address), i,
emailAddresses, level + 1);
//operation.run();
try {
final Future handler = poolMainExecutor.submit(operation);
try {
handler.get(Constant.TIME_OUT, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
handler.cancel(false);
}
} catch (Exception e) {
//System.out.println("Time out for:" + address);
} catch (Error error) {
//System.out.println("Time out for:" + address);
} finally {
}
}
Implement Callable<Void> instead of Runnable and wait for all the task to terminate by calling Future<Void>.get():
class SearchingOperation implements Callable<Void>
{
public Void call() throws Exception
{
//same code as in run()
}
}
//submit and wait until the task complete
Future<Void> future = poolMainExecutor.submit(new SearchingOperation()).get();
Use ThreadPoolExecutor.awaitTermination():
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
As in your code, you create your ThreadPoolExecutor first
ThreadPoolExecutor poolMainExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Constant.NUM_OF_THREAD);
Then, you need to add Tasks to it:
poolMainExecutor.execute(myTask);
poolMainExecutor.submit(myTask);
execute will return nothing, while submit will return a Future object. Tasks must implement Runnable or Callable. An object of SearchingOperation is a task for example. The thread pool will execute the tasks in parallel, but each task will be executed by one thread. That means to effectively use NUM_OF_THREAD Threads you need to add at least NUM_OF_THREAD Tasks.
(Optional) Once you got all jobs to work, shutdown your pool. This will prevent new tasks from being submitted. It won't affect running tasks.
poolMainExecutor.shutdown();
At the end, you need to wait for all Tasks to complete. The easiest way is by calling
poolMainExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
You should adjust the amount of time you want to wait for the tasks to finish before throwing an exception.
Now that the work is done, notify the user. A simple way is to call one of the Dialog presets from JOptionPane, like:
JOptionPane.showMessageDialog(null, "message", "title", JOptionPane.INFORMATION_MESSAGE);
It will popup a little window with title "title", the message "message", an "information" icon and a button to close it.
This code can be used., it will check whether the execution is completed in every 2.5 seconds.
do {
System.out.println("In Progress");
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (poolMainExecutor.getActiveCount() != 0);
System.out.println("Completed");
This question continues this question.
I am trying to stop thread that inserts rows to dabase, but I always got an exception
This part of code shows my thread's logic
public void run() {
String number = "";
try {
while (!Thread.currentThread().isInterrupted()) {
number = generateNumber();
database.insertOrUpdateRow(number);
}
} catch (SQLException ex) {
LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
}
}
I have googled how to stop thread correctly and found that I should just flag that thread is stopped.
So, this is what I got
public boolean stop() {
try {
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t != null) {
if (t.getName().contains("generate")) {
t.interrupt();
LOGGER.info(t.getName()+" is stopped");
}
}
}
} catch (Exception e) {
LOGGER.error("Exception when call stop: " + e.toString());
}
return true;
}
My stacktrace
[INFO] [qtp1804418913-32] INFO se.homework.hwbs.tasks.un.server.NumberQtyService
Impl - generate37 is stopped
[INFO] [generate37] ERROR se.homework.hwbs.tasks.un.server.threads.InsertRowThre
ad - exception while inserting number 34587 transaction rollback: serialization
failure
[INFO] [qtp1804418913-33] ERROR se.homework.hwbs.tasks.un.server.database.Databa
se - error select cnt by numberjava.sql.SQLTransactionRollbackException: transac
tion rollback: serialization failure
[INFO] [qtp1804418913-34] ERROR se.homework.hwbs.tasks.un.server.database.Databa
se - error select cnt by numberjava.sql.SQLTransactionRollbackException: transac
tion rollback: serialization failure
Thread stops, everything works, but this exceptions make me feel bad. Why are they happens? How to stop thread when I work with database in correct way?
Database is HsqlDB.
Instead of enumerating threads and selecting one by name, you might consider using a stop variable in your insert thread which can be directly controlled.
Consider this GeneratorThread:
public class GeneratorThread extends Thread {
protected static volatile boolean stop;
public static void stopExecution() {
stop = true;
}
public GeneratorThread() {
stop = false;
}
public void run() {
String number = "";
try {
while (!stop) {
number = generateNumber();
database.insertOrUpdateRow(number);
}
} catch (SQLException ex) {
//Any SQLException will terminate your thread. Is this wanted?!
LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
}
}
}
You can stop this by calling GeneratorThread.stopExecution() which will set the flag to false causing the current number to be the last inserted.
Of cause this implies that there will be only one GeneratorThread ever in your application.
Just as well, you might rethink your while and try-catch positions in run. This thread would end on any SQLException whatsoever. If you want to keep the thread running even if there are (temporary?) errors, you might want to do
while (!stop) {
String number = "";
try {
number = generateNumber();
database.insertOrUpdateRow(number);
} catch (SQLException ex) {
LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
}
}
I combined ideas of #Jan and #Fildor.
So, this is what I got
public class GeneratingThread extends Thread {
private final Logger LOGGER = LoggerFactory.getLogger(InsertRowThread.class);
private final Database database;
private boolean stop = false;
public GeneratingThread(Database database) {
this.database = database;
}
#Override
public void run() {
String number = "";
try {
while (!stop) {
number = generateNumber();
database.insertOrUpdateRow(number);
}
} catch (SQLException ex) {
LOGGER.error("exception while inserting number " + number + " " + ex.getMessage());
}
}
public void stopThread() {
this.stop = true;
}
private String generateNumber() {
int number = ThreadLocalRandom.current().nextInt(0, 100000);
String sb = Integer.toString(number);
while (sb.length() < 5) {
sb = "0" + sb;
}
return sb;
}
}
And this is my starting of thread
private final List<GeneratingThread> generatingThreads = new ArrayList<>();
GeneratingThread thread = new GeneratingThread(db);
thread.start();
generatingThreads.add(thread);
And stop it
for (GeneratingThread gt : generatingThreads) {
if (gt != null) {
gt.stopThread();
LOGGER.info("Thread is stopped");
}
}
Worked perfect for me. Thanks for discussion!
I'm trying to print out in order my Log statements instead of randomly after each ping? Should I use wait and notify from object class to allow each thread to finish? Not sure how to go about this.
Main class
public class Main
{
public static void main(String[] args)
throws InterruptedException, ExecutionException, IOException
{
Scan4SMB scan4Servers = new Scan4SMB();
List<String> networkNames = scan4Servers.doScan();
for (String networkName : networkNames)
{
LOG.CONSOLE.debug(networkName);
}
}
}
Scan class
public class Scan4SMB
{
private final int THREADS = 256;
private final int SMB_PORT = 445;
private List<String> smbNames = new ArrayList<String>();
private List<String> foundDevicesArray = new CopyOnWriteArrayList<String>();
private byte[] ip;
Scan4Servers() throws UnknownHostException
{
// this code assumes IPv4 is used
ip = Inet4Address.getLocalHost().getAddress();
LOG.CONSOLE.debug("LocalHost ip: " + ip);
}
Scan4Servers(Inet4Address address) throws UnknownHostException
{
ip = address.getAddress();
LOG.CONSOLE.debug("LocalHost IP: " + ip);
}
protected List<String> doScan() throws IOException
{
LOG.CONSOLE.debug("Start scanning");
ExecutorService executor = Executors.newFixedThreadPool(THREADS);
for (int i = 1; i <= 254; i++)
{
ip[3] = (byte) i;
InetAddress address = null;
try
{
address = InetAddress.getByAddress(ip);
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
executor.execute(pingRunnable(address));
}
LOG.CONSOLE.debug("Waiting for executor to terminate...");
executor.shutdown();
try
{
executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ignored)
{
}
LOG.CONSOLE.debug("Scan finished");
return smbNames;
}
private Runnable pingRunnable(final InetAddress address) {
return new Runnable() {
public void run() {
LOG.CONSOLE.debug("Pinging " + address + "...");
try {
Socket socket = new Socket(address, SMB_PORT);
LOG.CONSOLE.debug("Connection: " + socket.toString());
if (socket.isConnected()) {
LOG.CONSOLE.debug("connected " + address.toString());
String ipString = address.toString().substring(1,
address.toString().length());
NbtAddress[] addr = NbtAddress
.getAllByAddress(ipString);
String NETNAME = addr[0].firstCalledName();
// String NETNAME1 =
// addr[0].nextCalledName();
smbNames.add(NETNAME);
LOG.CONSOLE.debug("NETNAME " + NETNAME);
LOG.CONSOLE.debug("addr " + addr);
foundDevicesArray.add(address.toString());
LOG.CONSOLE.debug("hostname added to found "
+ address.toString());
socket.close();
}
socket.close();
} catch (UnknownHostException e) {
// LOG.CONSOLE.debug("Not found", e);
} catch (IOException e) {
// LOG.CONSOLE.debug("IO Error", e);
}
}
};
}
protected List<String> getList()
{
return smbNames;
}
}
There are many ways to do it. Here's one possible approach using a CountDownLatch -- a simple but versatile way to coordinate threads. I modified your pingRunnable to accept 2 latches. It will wait for the first latch before before printing any output. It will clear the second latch after it's done.
This way every Runnable will wait for the previous one to be done before printing anything. The scanning will still occur in parallel but the output will be synchronized.
Here's the modified loop in doScan method:
CountDownLatch lastLatch = new CountDownLatch(0);
for (int i = 1; i <= 254; i++) {
ip[3] = (byte) i;
InetAddress address = null;
try {
address = InetAddress.getByAddress(ip);
} catch (UnknownHostException e) {
e.printStackTrace();
}
CountDownLatch nextLatch = new CountDownLatch(1);
executor.execute(pingRunnable(address, lastLatch, nextLatch));
lastLatch = nextLatch;
}
And Here's the modified pingRunnable:
private Runnable pingRunnable(final InetAddress address, CountDownLatch waitFor, CountDownLatch clearWhenDone) {
return new Runnable() {
public void run() {
try {
Socket socket = new Socket(address, SMB_PORT);
waitFor.await(); // wait for all previous runners to log their output
LOG.CONSOLE.debug("Connection: " + socket.toString());
if (socket.isConnected()) {
LOG.CONSOLE.debug("connected " + address.toString());
String ipString = address.toString().substring(1,
address.toString().length());
NbtAddress[] addr = NbtAddress
.getAllByAddress(ipString);
String NETNAME = addr[0].firstCalledName();
// String NETNAME1 =
// addr[0].nextCalledName();
smbNames.add(NETNAME);
LOG.CONSOLE.debug("NETNAME " + NETNAME);
LOG.CONSOLE.debug("addr " + addr);
foundDevicesArray.add(address.toString());
LOG.CONSOLE.debug("hostname added to found "
+ address.toString());
socket.close();
}
socket.close();
} catch (UnknownHostException e) {
// LOG.CONSOLE.debug("Not found", e);
} catch (IOException e) {
// LOG.CONSOLE.debug("IO Error", e);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
} finally {
clearWhenDone.countDown(); // signal to the next Runnable that we are done
}
}
};
}
My understanding is that you want to run a bunch of tasks in parallel, (the ping), but you want the log messages to print in the order the tasks were submitted to the executor, but only after they are done.
We can do that.
// I'm taking some liberty with your code, so the concepts are highlighted
ExecutorService exec = ....;
// Important thing is to have a list of result futures
List<Future<String>> results = new ArrayList<>();
// we have some way to generate our work. For loop like above is fine.
List<String> addresses = imagineWeHaveAListOfAddresses();
for( String address : addresses ) {
// here we record the future returned by the ExecutorService
results.add(exec.submit(pingRunnable(address), address);
}
// result.get() is blocking, so we'll print the addresses in the same order we submitted them.
for( Future<String> result : results ) {
LOG.info("Finished address: " + result.get());
}
I hope that helps.
I have been implementing a program to compile and run other applications. I was wondering if there is a way to terminate a program when my application discovers that there is an issue e.g. infinite loop. I tried to using process.Destroy() but it kills the CMD not that actual program that has infinite loop...
Your help is really appreciated.
Here is a part of my code:
synchronized (pro) {
pro.wait(30000);
}
try{
pro.exitValue();
}catch (IllegalThreadStateException ex)
{
pro.destroy();
timeLimitExceededflag = true;
System.out.println("NOT FINISHED123");
System.exit(0);
}
}
Basically I am making my application to invoke the cmd using a processBuilder. This code terminates the CMD but if it runs a program that has an infinite loop that application will be still running which affects my servers performance.
I'd suggest to use the following solution:
start your program with a title specified
get PID of the process using "tasklist" command. A CSV parser required. There are tons of available I believe, like org.apache.commons.csv.CSVParser etc :)
kill the process by "taskkill" command using PID.
Here is some part of code which may be useful:
public static final String NL = System.getProperty("line.separator", "\n");
public <T extends Appendable> int command(String... cmd) throws Exception {
return command(null, cmd);
}
public <T extends Appendable> int command(T out, String... cmd) throws Exception {
try {
final ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
final Process proc = pb.start();
final BufferedReader rd = new BufferedReader(new InputStreamReader(proc.getInputStream()));
for (;;) {
final String line = rd.readLine();
if (line == null) {
break;
}
if (out != null) {
out.append(line);
out.append(NL);
}
}
return proc.waitFor();
} catch (InterruptedException e) {
throw new IOException(e);
}
}
public void startProcessWithTitle(String pathToExe, String title) throws Exception {
command("cmd.exe", "/C", "start", '"' + pathToExe + '"', '"' + title + '"', ..cmd.params..);
}
public int findProcessByTitle(String title) throws Exception {
final StringBuilder list = new StringBuilder();
if (command(list, "tasklist", "/V", "/FO", "csv") != 0) {
throw new RuntimeException("Cannot get tasklist. " + list.toString());
}
final CSVReader csv = new CSVReader(new StringReader(list.toString()), ',', true, "WindowsOS.findProcessByTitle");
csv.readHeaders(true); // headers
int pidIndex = csv.getHeaderIndex("PID");
int titleIndex = csv.getHeaderIndex("Window Title");
while (csv.nextLine()) {
final String ttl = csv.getString(titleIndex, true);
if (ttl.contains(title)) {
return csv.getInt(pidIndex);
}
}
Utils.close(csv);
return -1;
}
public boolean killProcess(int pid) throws Exception {
return command("taskkill", "/T", "/F", "/PID", Integer.toString(pid)) == 0;
}