Java 8: Kill/Stop a thread after certain period of time - java

I have a java 8 based project which performs a certain function on a url. I need to modify the code snippet below so that it is capable of killing the thread/process running and run the next instance after a certain period of time irrespective of current process status.
I tried the following techniques to implement the thread kill procedure:
Executor service
Timer Task
Multithreaded thread kill
The code snippet for my most recent attempt is linked below.
#SuppressWarnings("static-access")
public static void main(String[] args) {
//fetch url from the txt file
List<String> careerUrls = getCareerUrls();
int a = 0;
DBConnection ds = null;
ds = DBConnection.getInstance();
try (java.sql.Connection con = ds.getConnection()) {
//read a single Url
for (String url : careerUrls) {
int c = a++;
ExecutorService executor = Executors.newFixedThreadPool(3);
Future<?> future = executor.submit(new Runnable() {
#Override
// <-- job processing
public void run() {
long end_time = System.currentTimeMillis() + 10000;
System.out.println("STARTED PROCESSING URL: " + url);
jobareaDeciderSample w = new jobareaDeciderSample();
w.mainSample(url, c, con);
}
});
// <-- reject all further submissions
executor.shutdown();
try {
future.get(120, TimeUnit.SECONDS); // <-- wait 2 Minutes to finish
} catch (InterruptedException e) { // <-- possible error cases
System.out.println("job was interrupted");
future.cancel(true);
Thread.currentThread().interrupt();
;
} catch (ExecutionException e) {
System.out.println("caught exception: " + e.getCause());
} catch (TimeoutException e) {
System.out.println("timeout");
future.cancel(true);
}
// wait all unfinished tasks for 2 sec
if (!executor.awaitTermination(0, TimeUnit.SECONDS)) {
// force them to quit by interrupting
executor.shutdownNow();
}
}
} catch (Exception e) {
LOGGER.error(e);
}
}

You are correct with your approach.
calling cancel(true); on future is the right way to stop this task.
You have another problem- you cannot just stop a thread. (well you can, using stop() in thread class, but you should never do this).
cancel(true); sends information to the thread, that it should be stopped. Some java classes are responding to this information and throw interrupted exception. But some dont. You have to modify your task code, to check if Thread.currentThread().isInterrupted(), and if so, stop execution.
This is something you have to do in your code, which you call by
jobareaDeciderSample w = new jobareaDeciderSample();
w.mainSample(url, c, con);
You should do this in some long time spinning code, if you said you do some stuff with url, you should do it in your while loop, where you download information for the web. In other words, do this check only when your code spends 99% of the time.
Also you are calling
Thread.currentThread().interrupt();
in your main thread, this does not do anything for you, as if you want to quit current thread, you can just call return

Related

ExecutorService - Killing thread after some specified time limit

I have created ExecutorService and submitted a job. The job might be time-consuming. So I have given timeout as 2 seconds. If the execution takes more than 2 seconds, I want to kill that thread.
public void threadTest() {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(() -> {
try {
String threadName = Thread.currentThread().getName();
Thread.sleep(7000);
System.out.println("process completed after 7 seconds");
} catch (Exception e) {
e.printStackTrace();
}
}).get(2, TimeUnit.SECONDS);
}catch (Exception e){
}
executor.shutdown();
}
public static void main(String[] args) throws Exception {
System.out.println("main start");
ThreadBreaker tb = new ThreadBreaker();
tb.threadTest();
System.out.println("main end");
}
output
main start
main end
process completed after 7 seconds
The function threadTest exited after 2 seconds as I expected. But the submitted job kept running. I want to stop the submitted task if it couldn't complete in a given timeout.
Once you have submitted a task to executorService you've got an Future object. And you can cancel execution by Future.cancel(true) call.
Keep in mind that canceling the active running task is possible when you have accurate InterruptException handling inside a task.
In the example above:
Thread.sleep(7000);
will raise an interrupted exception and you should not catch it (or if you catched it re-raise another exception)
When you use ExecutorService you cannot kill Threads by yourself. ThreadPool decides when to kill a Thread (typically it might happen if the Thread was interrupted).
In your case you should catch the TimeoutException and cancel the Future. If your "real" task is responsive to interruption(invoking and handling InterruptedException correctly) it will work. Otherwise you should check the Thread.currentThread().isInterrupted() status in a loop.
Your example code will look like :
public void threadTest() {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> submit = executor.submit(() -> {
try {
String threadName = Thread.currentThread().getName();
Thread.sleep(7000);
System.out.println("process completed after 7 seconds");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); //preserve interruption status. based on this ThreadPool's interruption Policy will decide what to do with the Thread
}
});
try {
submit.get(2, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); //handle this
} catch (TimeoutException e) {
submit.cancel(true); //cancel the task
}
executor.shutdown();
}
Also remember that if you execute a task in a ThreadPool and you execute operations that might from InterruptedException in most cases you should preserve the interruption status.

What is the best strategy in setting up an autosave timer to save a file periodically in java (but without using any javafx API)?

Say I need to autosave a file every 15 minutes periodically.
I've looked at How to set a Timer in Java? as a reference.
There are times the machine would be putting under the power saving mode.
After the app is being brought back running, the thread that the timer is on will need to be resumed from the time elapsed before being suspended from the power saving but NOT restarting it from scratch.
Will the use of ExecutorService and Future be the best in this case and how ?
What do I do when I capture any of the following exceptions so that I can resume and reinstate the autosave timer ?
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = new Runnable() {
#Override
public void run() {
saveFile();
}
};
Future<?> f = service.submit(r);
f.get(15, TimeUnit.MINUTES); // attempt the task for 15 minutes
}
catch (final InterruptedException e) {
// The thread was interrupted during sleep, wait or join
// how to redo the countdown ?
}
catch (final TimeoutException e) {
// Took too long!
// what to do ?
}
catch (final ExecutionException e) {
// An exception from within the Runnable task
// what to do ?
}
finally {
service.shutdown();
}

Ping a server without freezing the Thread

I tried to use multiple threads, sadly no luck:
public synchronized boolean pingServer(final String ip, final short port) {
final boolean[] returnbol = new boolean[1];
Thread tt = new Thread(new Runnable() {
#Override
public void run() {
try {
Socket s = new Socket(ip, port);
s.close();
returnbol[0] = true;
} catch (IOException e) {
returnbol[0] = false;
}
}
});
tt.start();
try {
tt.join();
} catch (InterruptedException e) {
tt.stop();
}
tt.stop();
return returnbol[0];
}
The main thread still Freezes for some reason.
Is there a "lagless" way to ping a server?
What exactly did you want to got in
try {
tt.join();
} catch (InterruptedException e) {
tt.stop();
}
block?
Here you joined to parallel thread and waits till this thread will ends (got ping result).
You have next options:
Wait till ping ends
Don't wait... and don't got result
Use some concurrency classes like Future<> to got result (but you will block thread at moment you ask result if it not retrieved yet)
Or you can use some 'callback' function/interface to threw result from inner 'ping' thread.
You will need to remove the following lines from your code.
The tt.join() will force the main thread to wait for tt to finish.
try {
tt.join();
} catch (InterruptedException e) {
tt.stop();
}
tt.stop();
Use a Future instead to get the result for later use

CompletionService - submit() does not block to ensure all threads are created

I am submitting Callables to an ExecutorCompletionService and it seems like the submit() method does not block code while submitting Callables. Here is the code that I have:
ExecutorService executor = Executors.newFixedThreadPool(30);
BlockingQueue<Future<Data>> completionQueue = new LinkedBlockingQueue();
ExecutorCompletionService<Data> completionService = new ExecutorCompletionService<Data>(executor, completionQueue);
while(receivingPackets) {
Callable<Data> splitPacketCallable = new SplitPacket(packetString);
completionService.submit(splitPacketCallable);
try {
// Allow submit to finish
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ex) {
System.out.println("Something went wrong with sleeping");
}
try {
Future<Data> dataFuture = completionService.poll();
if (dataFuture != null) {
Data data = dataFuture.get();
fileWriter.writeLine(data.toString());
}
} catch (InterruptedException ex) {
System.out.println("Error from poll: " + ex.toString());
} catch (ExecutionException ex) {
System.out.println("Error from get: " + ex.toString());
}
}
// Finish any remaining threads
while (!completionQueue.isEmpty()) {
try {
Future<Data> dataFuture = completionService.take();
Data data = dataFuture.get();
fileWriter.writeLine(data.toString());
} catch (InterruptedException ex) {
System.out.println("Error from take: " + ex.toString());
} catch (ExecutionException ex) {
System.out.println("Error from get: " + ex.toString());
}
}
fileWriter.close();
executor.shutdown();
A few things to note:
Data is a class that stores data in a special format. SplitPacket is a class that implements Callable that takes in a String that has arrived and splits it into chunks to be saved in Data. fileWriter and its method writeLine is a Runnable Class that will asynchronously write to a single file from multiple threads.
If I play with the sleep in the for loop, I start getting inconstant results in my output file. If I sleep for 50 ms every time I submit a Callable, everything works perfectly. However, if I submit with a low value (say 0-5 ms), I start getting dropped threads in the output. To me, this implies that the submit() method of ExecutorCompletionService does not block. However, because blocking a submitted callable seems vital, I also assume I am just implementing this wrong.
In my case, I don't know how many packets will be coming in so I need to be able to continuously add Callables to the Executor. I have tried this with a for loop instead of a while loop so that I can send a given number of packets and see if they get printed on the other end, and I can only get them to go through if I have a delay after submit.
Is there a way to fix this without adding a hack-y delay?
If you look at the source of ExecutorCompletionService you will see that the Futures are being added to completionQueue after the task is marked as done.
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
You may have an empty queue but still running tasks.
The simplest thing you can do is just count the tasks.
int count = 0;
while(receivingPackets) {
...
completionService.submit(splitPacketCallable);
++count;
...
try {
Future<Data> dataFuture = completionService.poll();
if (dataFuture != null) {
--count;
...
}
...
}
// Finish any remaining threads
while (count-- > 0) {
...
}

How to interrupt a task in progress with a timeout mechanism?

I'm currently developping a ftp client based on the package commons.net, in order to run tests to see the speed of the connection.
Basically my ftp test consists in connect to the server, logging onto it, and then start a cycle of download/upload as long as necessary, until the user decides to stop it via a button, then the current cycle will end and so will the test.
However, while running those tests, a situation requiering a timout mechanism has occured. the server was transmitting the file, and send the return code 226 (transfer complete) before it was indeed completed.
So my thread remains stuck, trying to empty the inputStream when it is not possible anymore.
My idea was to start a threaded timer with the downloading process, that will be reset each time a byte is transferred to my client.
When the timeout occurs, then an exception or so would be raised, and my client would react to it, abording the download.
I have read and try many solutions, among them:
- raising an exception from a thread -> the thread catches the exception and not the client;
- interrupt the client from the thread, so the client raises itself an interruptedException -> doesn't seem to work;
- using an executor with a timeout -> since I can't know the "normal" duration of a download, I can't give it to the executor when I start the task, moreover, the timer has to be reset when I receive data.
I read a lot about it on many forums, and didn't find any solution that seem to be adapted AND work in this case. If anyone has an idea of another way to do it?
This is the code of the action I am performing:
public double get(String fileName) {
[...]
org.apache.commons.net.io.Util.copyStream(stO,stD,client.getBufferSize(),
this.localSize,
new org.apache.commons.net.io.CopyStreamAdapter() {
public void bytesTransferred(long totalBytesTransferred,
int bytesTransferred,long streamSize) {
setProgressDL(totalBytesTransferred);
//reset the timer here
}
});
[...]
}
Here is some of the code of my test, launching my client:
public class TestFtp extends Thread {
[...]
public void run() {
System.out.println("Launching FTP test");
FtpClient client = new FtpClient(this.model, this, this.model.getFtpServer());
try {
//Attempting connection on the server
client.connect();
try {
// Attempting login
client.login(this.model.getUsername(), this.model.getPassword());
do {
client.changeDirectory("get");
// start timer
client.get(this.model.getDistantFileName());
// stop timer
client.changeToParentDirectory();
client.changeDirectory("put");
client.set(this.model.getDistantFileName(),
this.model.getNewFileName());
client.changeToParentDirectory();
try {
// Little pause between each test
Thread.sleep(500);
} catch (InterruptedException e) {}
// Continue test until the user stops it
} while (this.continuous);
// Once the test is over, logout
client.logout();
} catch (FTPLoginException e) {
// If login fails, the test ends
System.out.println("Unable to login to the server.");
}
} catch (FTPConnectException e) {
// If connection error, the test ends
System.out.println("Unable to connect to the server.");
}
}
Thank you by advance if anyone can help, and if you need further information on my actual code, I can put more of it in here.
If you do not want to throw unecessary Exceptions, you should use a boolean flag that controls the execution of the thread (or runnable):
public class TestFtp extends Thread {
[...]
boolean abort;
public void run() {
[...]
do{
[...]
} while (this.continuous && !abort);
if (abort){
// You might want to do something here
}else{
// The stuff you normally do
}
}
}
And then simply set the abort flag to false from outside.
This way you can better control how you thread will terminate, as thread.interrupt(); will have an undefined behavior.
Well, I'm sorry but I admit I haven't read all your code, but if you want to interrupt a running thread, do two things:
run the thread code inside a try/catch block like this:
Example:
public void run() {
try {
// code to run
} catch (InterruptedException ie) {
// thread interrupted, may want to do some clean up
// but must return as quickly as possible to avoid halting external code
}
}
Call the interrupt() method of the thread above externally when the need arises.
Example:
thread.interrupt();
This will tell the VM to throw the InterruptedException in your thread no matter what it's doing, giving you a chance to do some stuff.
I hope this is what you're looking for...
EDIT
Ok, a concrete example that works:
public class Driver {
private static int count = 0;
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
bigTask();
} catch (InterruptedException ie) {
System.out.println("Interrupted thread! Count is " + count);
}
}
});
t.start();
try {
Thread.sleep(1000);
System.out.println("Trying to interrupt thread");
t.interrupt();
} catch (InterruptedException e) {}
}
private static void bigTask() throws InterruptedException {
List<BigDecimal> bigs = new ArrayList<BigDecimal>();
for (int i = 0; i < 10000000; i++) {
bigs.add(BigDecimal.valueOf(i));
if (Thread.interrupted()) {
throw new InterruptedException();
}
count = i;
}
System.out.println("Ok, added ten million items, count is " + count);
}
}

Categories