Given that I have the following test-code:
import java.util.concurrent._
object TestTime {
def main(args: Array[String]) {
println("starting....")
val service = Executors.newSingleThreadExecutor
val r = new Callable[Unit]() {
override def call(): Unit = {
//your task
val t0 = System.nanoTime
val total = sum(1000000000)
val t1 = System.nanoTime
println("Elapsed time " + (t1 - t0) / 1e9 + " secs")
println(s"total = $total")
}
}
val f = service.submit(r)
try {
// attempt the task for 2 second
f.get(2, TimeUnit.SECONDS)
} catch {
case _: TimeoutException =>
f.cancel(true)
println(s"Timeout....")
} finally {
service.shutdown()
}
println("after 2 seconds....")
for(i <- 1 to 2){
println(s"$i ...")
Thread.sleep(1000)
}
println("main thread ends...")
}
//Given that sum() is written by others and I cannot change it.
def sum(k: Int): BigInt = {
var total: BigInt = 0
for (i <- 1 to k) {
total += i
}
total
}
}
I would like to execute the sum at most 2 seconds. If it exceeds the time limit, the corresponding thread should be interrupted immediately. To interrupt that thread, I have tried two methods when catch TimeoutException:
f.cancel(true)
service.shutdownNow()
However, according to my test, the above methods cannot interrupt the thread.
So I would like to know is there method to interrupt a thread compulsively.
According to JavaDocs for both Future#cancel and ExecutorService#shutdownNow, the typical implementation is that these methods result in interrupting the underlying thread.
If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
Note particuarly the last comment. Thread interruption via the Thread#interrupt method is a cooperative process. When one thread interrupts another, it results in setting the target thread's interrupted status. Also, if the target thread is blocked in certain specific methods, then that thread will experience an InterruptedException.
If the code executing in the target thread neither checks for interrupted status periodically via the Thread#isInterrupted method nor calls a blocking method and handles InterruptedException, then interruption effectively does nothing. That code is not cooperating in the interruption process, so there is effectively no way to shut it down, despite thread interruption.
//Given that sum() is written by others and I cannot change it.
Ideally, long-running code intended for execution in background threads would be changed to cooperate in the thread interruption. In your example, a viable technique would be to change sum to check Thread#isInterrupted every N iterations of the for loop, and if interrupted, abort the loop. Then, it could either throw an exception to indicate that it didn't complete or possibly return some sentinel BigInt value to indicate the abort if that's appropriate.
If the invoked code truly cannot be changed, then you cannot halt it by thread interruption. You could potentially use daemon threads so that at least these threads won't block JVM exit during shutdown.
Related
My program has a thr () function that returns a string value, but before returning, the value is overridden in Thread, but when called in main (), this function will return the string that was before being processed in Thread. If you add Sleep, everything will be fine before, but I think this is not a good solution to the problem. If there are suggestions on how to solve this problem, then it would be bad.
Code:
fun main() {
println(thr())
}
fun thr(): String {
var x = "Before thread"
Thread {
x = "After thread"
}.start()
// Thread.sleep(100)
return x
}
The desired result is - "After thread"
The current result - "Before thread"
You have a race condition, because the value of x at the return statement depends on whether your created thread has run and executed that line yet - Thread.sleep just makes the current thread (the one that's executing thr(), not the one you're creating) wait so the new one has a chance to finish.
There's also the issue that the value of x that Thread 1 sees might not be what Thread 2 sees, so it won't see the updated value at the point where it's returning it. This is down to some under-the-hood memory trickery that improves performance, and it's why you need to handle synchronization.
Basically you need to read up on concurrency and the different ways it can be handled. This is for Java but it's the basics of what's going on with threading in Kotlin too:
https://docs.oracle.com/javase/tutorial/essential/concurrency/
You need to be aware of this stuff in general, so it's worth getting your head around it!
I guess what you want to do is to wait for the thread to finish and then return x. In this case, you can use the join method:
fun thr(): String {
var x = "Before thread"
val t = Thread {
x = "After thread"
}
t.start()
t.join()
return x
}
I've made a small code for practising with Executors and Threads. It consists of the following:
Create a fixed-thread pool of size 3 with an infinite queue.
Submit 3 tasks with infinite loop (while(true)) to the pool (then
all threads are occupied)
Submit a 4th task, which is going to be waiting in the queue.
executor.shutdown() and doing a println for seeing how make active task and task count do i have.
setting the flag to false in order to stop the infinite while and then doing a
println for seeing how make active task and task count do i have
cancelling all futures with mayInterruptIfRunning=true and then
doing a println for seeing how make active task and task count do i
have
This is the code:
public class Main {
private static ThreadPoolExecutor fixexThreadPool;
public static void main(String[] args) throws InterruptedException {
System.out.println("Creating fixed thread pool of size 3 and infinite queue.");
fixexThreadPool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
final Boolean[] flag = new Boolean[1];
flag[0] = true;
List<Future> futures = new ArrayList<>();
System.out.println("Submiting 3 threads");
for (int i = 0; i < 3; i++) {
futures.add(fixexThreadPool.submit(() -> {
int a = 1;
while (flag[0]) {
a++;
}
System.out.println("Finishing thread execution.");
}));
}
System.out.println("Done submiting 3 threads.");
System.out.println(String.format("Active count: %s | Completed task count: %s | task count: %s", fixexThreadPool.getActiveCount(), fixexThreadPool.getCompletedTaskCount(), fixexThreadPool.getTaskCount()));
Thread.sleep(3000L);
System.out.println("Submitting a 4th thread.");
futures.add(fixexThreadPool.submit(() -> {
int a = 1;
while (flag[0]) {
a++;
}
System.out.println("Finishing thread execution");
}));
System.out.println(String.format("Active count: %s | Completed task count: %s | task count: %s", fixexThreadPool.getActiveCount(), fixexThreadPool.getCompletedTaskCount(), fixexThreadPool.getTaskCount()));
System.out.println("Executor shutdown");
fixexThreadPool.shutdown();
System.out.println(String.format("Active count: %s | Completed task count: %s | task count: %s", fixexThreadPool.getActiveCount(), fixexThreadPool.getCompletedTaskCount(), fixexThreadPool.getTaskCount()));
Thread.sleep(2000L);
System.out.println("Setting flag to false.");
flag[0] = false;
Thread.sleep(2000L);
System.out.println(String.format("Active count: %s | Completed task count: %s | task count: %s", fixexThreadPool.getActiveCount(), fixexThreadPool.getCompletedTaskCount(), fixexThreadPool.getTaskCount()));
System.out.println("Cancelling all futures.");
futures.forEach(f -> f.cancel(true));
System.out.println(String.format("Active count: %s | Completed task count: %s | task count: %s", fixexThreadPool.getActiveCount(), fixexThreadPool.getCompletedTaskCount(), fixexThreadPool.getTaskCount()));
}
}
This is the output of the execution:
Creating fixed thread pool of size 3 and infinite queue.
Submiting 3 threads
Done submiting 3 threads.
Active count: 3 | Completed task count: 0 | task count: 3
Submitting a 4th thread.
Active count: 3 | Completed task count: 0 | task count: 4
Executor shutdown
Active count: 3 | Completed task count: 0 | task count: 4
Setting flag to false.
Active count: 3 | Completed task count: 0 | task count: 4
Cancelling all futures.
Active count: 3 | Completed task count: 0 | task count: 4
There are a couple of things i don't understand.
Why, after shutting down executor, there still are active threads ?
Why, after changing the flag to false in order to break the infinite loop, the infinite while doesn't break ?
Why, after cancelling every future, there is are active threads ?
No matter if a change the flag to false, shutdown executor or even cancelling all futures, my program doesn't stop running. Why is that?
Thanks in advance!!
This issue can be solved by making use of the volatile keyword. This thread provides a wealth of answers explaining what volatile is in detail and there are plenty of tutorials/sources/blogs out there that can provide further detail. Another super detailed thread about volatile here.
Honestly, there are many many people on the internet that can explain it better and more accurately than I ever could, but in short - volatile is a Java modifier and should be used when you have a resource that is being shared by multiple threads. It tells the JVM to make sure that each threads cached value is synchronized with the value in main memory.
Clearly the JVM is falling over somewhere and the value the threads are holding doesn't quite match the actual value. A small change to your implementation can fix this :
Make the flag a class instance variable
private volatile static Boolean[] flag = new Boolean[1];
See here for why I did this.
So to give the slightly bigger picture:
private static ThreadPoolExecutor fixexThreadPool;
private volatile static Boolean[] flag = new Boolean[1];
public static void main(String[] args) throws InterruptedException {
System.out.println("Creating fixed thread pool of size 3 and infinite queue.");
fixexThreadPool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
flag[0] = true;
List<Future> futures = new ArrayList<>();
System.out.println("Submiting 3 threads");
...
The code now happily stops without any issues, hope this helps :)
(on a side note, curious as to why you used Boolean[] and not just a Boolean? I kept it as is for consistency in my answer but it also works obviously with flag just being a Boolean rather than an array)
-- Edit --
To answer your recent comment - I'm affraid my understanding pretty much stops with what I have already written, but I can provide my thoughts on it. It appears that the reason your app doesn't "exit" when you call fixexThreadPool.shutdown(); can be found in the documentation for ThreadPoolExecutor. Namely -
public void shutdown()
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
The while loop has already been submitted, and so it will happily carry on executing.
I explored this a bit to see what was happening.
Firstly I didn't enjoy that long status log line so I created a separate method for it! I also noticed a few interesting Boolean state in the ThreadPoolExecutor and Future's so decided to log them too:
private static void Log() {
System.out.println(String.format("\nActive count: %s | Completed task count: %s | task count: %s",
fixexThreadPool.getActiveCount(),
fixexThreadPool.getCompletedTaskCount(),
fixexThreadPool.getTaskCount()));
System.out.println(String.format("isShutdown : %s | isTerminated : %s | isTerminating : %s ",
fixexThreadPool.isShutdown(),
fixexThreadPool.isTerminated(),
fixexThreadPool.isTerminating()));
System.out.println(String.format("Futures size = %s", futures.size()));
futures.forEach(f -> System.out.println(String.format("Future isCancelled : %s | isDone : %s", f.isCancelled(), f.isDone())));
System.out.println("");
}
Placing this into your code, we get:
Log();
System.out.println("Executor shutdown");
fixexThreadPool.shutdown();
Log();
Thread.sleep(2000L);
System.out.println("Setting flag to false.");
flag[0] = false;
Thread.sleep(2000L);
Log();
System.out.println("Cancelling all futures.");
futures.forEach(f -> System.out.println(String.format("Future cancelled - %s", f.cancel(true))));
Log();
I also wanted to add a quick heartbeat to the app, printing a every now and then so i could see what was/wasn't still running behind the scenes:
private static void Heartbeat(int a) {
int amod = a % 1000000000;
if(amod == 0) {
System.out.println(a);
}
}
In use:
while (flag[0]) {
a++;
Heartbeat(a);
}
I then ran a few test runs, trying some different things, in different combinations:
comment out fixexThreadPool.shutdown();
comment out futures.forEach(f -> f.cancel(true));
comment out flag[0] = false;
try with/without the new volatile fix.
To keep an already very long answer a little bit shorter, feel free to explore combinations of these yourself, but I found that
without the volatile keyword, the threads were stuck in terminating
state. I can only assume that shutdown() does not stop the while
loops from doing what their doing as these tasks have already been submitted and so as none of the threads think
flags[0] == false, they will carry on incrementing a.
As far as I can see, this exhibits the behavior outlined in the documentation. So shutdown isnt stopping your while loops, it just stops any new future's being submitted to the thread pool (and being added to the blocking queue), then waits paitently for the while loops to complete (which obviously without the volatile modifier on the flag, they never will).
Using volatile, but commenting out the shutdown, obviously, each task
terminates (console logs 4 "Finishing thread execution.") but the
thread pool stays active and the program itself does not terminate. The pool is patiently waiting for new tasks, which it obviously never gets.
The `future.cancel' logic is a bit beyond my understanding currently. I ran a test calling just future.cancel and did some deeper logging/investigation but don't really have a concrete answer.
My running theory is that the future's have already been added to the blocking queue in the thread pool and so calling cancel doesn't do anything to affect the thread pool's execution, and so effectively calling future.cancel on its own does absolutely nothing to fixexThreadPool.
Hopefully this provides plenty of food for thought :)
Why, after shutting down executor, there still are active threads?
By invoking shutdown, we request a normal shutdown. The thread pool stops accepting new tasks but waits for the already submitted tasks to complete - running or queued. So the shutdown method doesn't try to stop the threads. And conceptually, the ExecutorService implementations separate the task submission from the task execution. In other words, we own the tasks but not the threads.
Why, after changing the flag to false in order to break the infinite
loop, the infinite while doesn't break?
We're using a cancellation flag here. But according to the Java memory model, for multiple threads to see the changes made to the shared data - flag - we must either employ synchronization or use the volatile keyword. So while synchronization provides both mutual exclusion and memory visibility, the volatile keyword just provides the memory visibility. Since only the main thread modifies the flag variable here, defining flag as a static volatile variable will make it work as expected.
public class Main {
private static ThreadPoolExecutor fixexThreadPool;
private static volatile Boolean[] flag = new Boolean[1];
// the main method
}
Why, after canceling every future, there is are active threads ?
ThreadPoolExecutor uses the FutureTask class as the Future implementation by default. And FutureTask cancels by interrupting the worker thread. So one can expect thread interruption to stop the task and even terminate the thread. But thread interruption is a cooperative mechanism. Firstly the task must be responsive to interrupts. It must check the interruption flag with Thread.isInterrupted and exit if possible. Secondly, the thread owner, in our case the thread pool, must check the interruption status and act accordingly. In this example, the task isn't responsive to interrupts. It uses a flag to cancel its operation. So let's continue with the thread owner. ThreadPoolExecutor doesn't act on the interruption status, so it doesn't terminate the thread.
No matter if a change the flag to false, shutdown executor or even
canceling all futures, my program doesn't stop running. Why is that?
As mentioned above, the current task uses the cancellation flag approach. So using the volatile keyword must solve the problem. Then the tasks will stop as intended. Cancellation, on the other hand, won't have any effect on the current task. Because it isn't checking the interruption status. We can make it responsive like this:
while (flag[0] && !Thread.currentThread().isInterrupted())
This way, the task also supports the cancellation by a thread interrupt.
Suppose I have the following code:
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync( () -> 0);
thenApply case:
future.thenApply( x -> x + 1 )
.thenApply( x -> x + 1 )
.thenAccept( x -> System.out.println(x));
Here the output will be 2. Now in case of thenApplyAsync:
future.thenApplyAsync( x -> x + 1 ) // first step
.thenApplyAsync( x -> x + 1 ) // second step
.thenAccept( x -> System.out.println(x)); // third step
I read in this blog that each thenApplyAsync are executed in a separate thread and 'at the same time'(that means following thenApplyAsyncs started before preceding thenApplyAsyncs finish), if so, what is the input argument value of the second step if the first step not finished?
Where will the result of the first step go if not taken by the second step?
the third step will take which step's result?
If the second step has to wait for the result of the first step then what is the point of Async?
Here x -> x + 1 is just to show the point, what I want know is in cases of very long computation.
The difference has to do with the Executor that is responsible for running the code. Each operator on CompletableFuture generally has 3 versions.
thenApply(fn) - runs fn on a thread defined by the CompleteableFuture on which it is called, so you generally cannot know where this will be executed. It might immediately execute if the result is already available.
thenApplyAsync(fn) - runs fn on a environment-defined executor regardless of circumstances. For CompletableFuture this will generally be ForkJoinPool.commonPool().
thenApplyAsync(fn,exec) - runs fn on exec.
In the end the result is the same, but the scheduling behavior depends on the choice of method.
You're mis-quoting the article's examples, and so you're applying the article's conclusion incorrectly. I see two question in your question:
What is the correct usage of .then___()
In both examples you quoted, which is not in the article, the second function has to wait for the first function to complete. Whenever you call a.then___(b -> ...), input b is the result of a and has to wait for a to complete, regardless of whether you use the methods named Async or not. The article's conclusion does not apply because you mis-quoted it.
The example in the article is actually
CompletableFuture<String> receiver = CompletableFuture.supplyAsync(this::findReceiver);
receiver.thenApplyAsync(this::sendMsg);
receiver.thenApplyAsync(this::sendMsg);
Notice the thenApplyAsync both applied on receiver, not chained in the same statement. This means both function can start once receiver completes, in an unspecified order. (Any assumption of order is implementation dependent.)
To put it more clearly:
a.thenApply(b).thenApply(c); means the order is a finishes then b starts, b finishes, then c starts.
a.thenApplyAsync(b).thenApplyAsync(c); will behave exactly the same as above as far as the ordering between a b c is concerned.
a.thenApply(b); a.thenApply(c); means a finishes, then b or c can start, in any order. b and c don't have to wait for each other.
a.thenApplyAync(b); a.thenApplyAsync(c); works the same way, as far as the order is concerned.
You should understand the above before reading the below. The above concerns asynchronous programming, without it you won't be able to use the APIs correctly. The below concerns thread management, with which you can optimize your program and avoid performance pitfalls. But you can't optimize your program without writing it correctly.
As titled: Difference between thenApply and thenApplyAsync of Java CompletableFuture?
I must point out that the people who wrote the JSR must have confused the technical term "Asynchronous Programming", and picked the names that are now confusing newcomers and veterans alike. To start, there is nothing in thenApplyAsync that is more asynchronous than thenApply from the contract of these methods.
The difference between the two has to do with on which thread the function is run. The function supplied to thenApply may run on any of the threads that
calls complete
calls thenApply on the same instance
while the 2 overloads of thenApplyAsync either
uses a default Executor (a.k.a. thread pool), or
uses a supplied Executor
The take away is that for thenApply, the runtime promises to eventually run your function using some executor which you do not control. If you want control of threads, use the Async variants.
If your function is lightweight, it doesn't matter which thread runs your function.
If your function is heavy CPU bound, you do not want to leave it to the runtime. If the runtime picks the network thread to run your function, the network thread can't spend time to handle network requests, causing network requests to wait longer in the queue and your server to become unresponsive. In that case you want to use thenApplyAsync with your own thread pool.
Fun fact: Asynchrony != threads
thenApply/thenApplyAsync, and their counterparts thenCompose/thenComposeAsync, handle/handleAsync, thenAccept/thenAcceptAsync, are all asynchronous! The asynchronous nature of these function has to do with the fact that an asynchronous operation eventually calls complete or completeExceptionally. The idea came from Javascript, which is indeed asynchronous but isn't multi-threaded.
This is what the documentation says about CompletableFuture's thenApplyAsync:
Returns a new CompletionStage that, when this stage completes
normally, is executed using this stage's default asynchronous
execution facility, with this stage's result as the argument to the
supplied function.
So, thenApplyAsync has to wait for the previous thenApplyAsync's result:
In your case you first do the synchronous work and then the asynchronous one. So, it does not matter that the second one is asynchronous because it is started only after the synchrounous work has finished.
Let's switch it up. In some cases "async result: 2" will be printed first and in some cases "sync result: 2" will be printed first. Here it makes a difference because both call 1 and 2 can run asynchronously, call 1 on a separate thread and call 2 on some other thread, which might be the main thread.
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync(() -> 0);
future.thenApplyAsync(x -> x + 1) // call 1
.thenApplyAsync(x -> x + 1)
.thenAccept(x -> System.out.println("async result: " + x));
future.thenApply(x -> x + 1) // call 2
.thenApply(x -> x + 1)
.thenAccept(x -> System.out.println("sync result:" + x));
The second step (i.e. computation) will always be executed after the first step.
If the second step has to wait for the result of the first step then what is the point of Async?
Async means in this case that you are guaranteed that the method will return quickly and the computation will be executed in a different thread.
When calling thenApply (without async), then you have no such guarantee. In this case the computation may be executed synchronously i.e. in the same thread that calls thenApply if the CompletableFuture is already completed by the time the method is called. But the computation may also be executed asynchronously by the thread that completes the future or some other thread that calls a method on the same CompletableFuture. This answer: https://stackoverflow.com/a/46062939/1235217 explained in detail what thenApply does and does not guarantee.
So when should you use thenApply and when thenApplyAsync? I use the following rule of thumb:
non-async: only if the task is very small and non-blocking, because in this case we don't care which of the possible threads executes it
async (often with an explicit executor as parameter): for all other tasks
In both thenApplyAsync and thenApply the Consumer<? super T> action passed to these methods will be called asynchronously and will not block the thread that specified the consumers.
The difference have to do with which thread will be responsible for calling the method Consumer#accept(T t):
Consider an AsyncHttpClient call as below: Notice the thread names printed below. I hope it give you clarity on the difference:
// running in the main method
// public static void main(String[] args) ....
CompletableFuture<Response> future =
asyncHttpClient.prepareGet(uri).execute().toCompletableFuture();
log.info("Current Thread " + Thread.currentThread().getName());
//Prints "Current Thread main"
thenApply Will use the same thread that completed the future.
//will use the dispatcher threads from the asyncHttpClient to call `consumer.apply`
//The thread that completed the future will be blocked by the execution of the method `Consumer#accept(T t)`.
future.thenApply(myResult -> {
log.info("Applier Thread " + Thread.currentThread().getName());
return myResult;
})
//Prints: "Applier Thread httpclient-dispatch-8"
thenApplyAsync Will use the a thread from the Executor pool.
//will use the threads from the CommonPool to call `consumer.accept`
//The thread that completed the future WON'T be blocked by the execution of the method `Consumer#accept(T t)`.
future.thenApplyAsync(myResult -> {
log.info("Applier Thread " + Thread.currentThread().getName());
return myResult;
})
//Prints: "Applier Thread ForkJoinPool.commonPool-worker-7"
future.get() Will block the main thread .
//If called, `.get()` may block the main thread if the CompletableFuture is not completed.
future.get();
Conclusion
The Async suffix in the method thenApplyAsync means that the thread completing the future will not be blocked by the execution of the Consumer#accept(T t) method.
The usage of thenApplyAsync vs thenApply depends if you want to block the thread completing the future or not.
For e.g. if I have a thread pool of two threads, but want each thread to be dedicated to a single type of task. i.e. task 1 can only execute on thread 1 of the pool , task 2 on thread 2 of the pool. I dont want more than two threads and I dont want two task1(s) to run simultaneously (one on each thread). Possible??
No, not possible. That's the benefit of using a thread pool: the pool will choose which thread will execute the delivered task. Note that even if you use Executors#newFixedThreadPool(2), you will have a thread pool with 2 threads, but this doesn't guarantee that each task is executed in a different thread.
If you need your tasks to be executed in different particular threads, then create your own threads instead. In case you don't want to manually create the threads, then use 2 single threaded executors. You can create them by using Executors#newSingleThreadExecutor (but this is very cumbersome).
Although there already is an accepted answer, you must use an AtomicBoolean instead of a volatile.
Like in
AtomicBoolean task1RunningAB = new AtomicBoolean( false);
Runnable task1 = () -> {
// compareAndSet( E, N) sets the value to N if current value matches E.
// Returns true if that was the case, so we must negate here
if ( ! task1RunningAB.compareAndSet( false, true))
return;
try {
// your code
} finally {
task1RunningAB.set( false);
}
};
If you wanna make sure a single task isn't being executed twice at the same time, use a boolean to specify whether that task is running or not:
(Java 8+)
volatile boolean task1Running = false;
Runnable task1 = () -> {
if(task1Running)
return; //already running, exit
task1Running = true;
//handle task
task1Running = false;
};
Now when you try to execute it while it's already running, it'll exit. volatile is to ensure that when we change task1Running from the Thread managing the task, all other threads (specifically, the thread that executes the tasks) will see it right away.
Following piece is from a JUnit testcase that tests 4 different implementations of Sorter. It invokes the only method Sorter has viz sort().
I want to kill the sorting process if it takes longer than say 2 seconds (Because I don't care for any implementation that takes longer than 2 seconds to sort() say 500000 Integers).
I'm new the Java multi-threading and after looking at all other threads ( How to kill a java thread? and a few others) on SO, I figured following as solution to my problem. Question is, would it work consistently, or could there be any issues? I don't care abt the array or it's contents as reset() would reset it's contents.
Reason why I call it uncooperative is because s.sort() is out of my control.
protected E[] arr;
#Test
public void testSortTArray() {
boolean allOk = true;
for (Sorter s : TestParams.getSorters()) {
System.out.println("Testing: " + s.getName() + " with " + arrayLenToTestWith + " elems of type "
+ classOfElemType.getName());
reset();
long startTime = System.nanoTime();
MyThread test = new MyThread(s, arr);
test.start();
try {
test.join(TestParams.getTimeThreshold());
} catch (InterruptedException e) {
e.printStackTrace();
}
if (test.isAlive())
test.interrupt();
if (!test.isInterrupted()) {
System.out.println("Time taken: " + ((System.nanoTime() - startTime) / (1000000)) + "ms");
if (!isSorted(arr)) {
allOk = false;
System.err.println(s.getName() + " didn't sort array.");
}
} else {
allOk = false;
System.err.println(s.getName() + " took longer than .");
}
}
assertTrue("At least one algo didn't sort the array.", allOk);
}
public class MyThread extends Thread {
private Sorter s;
private E[] arr;
public MyThread(Sorter s, E[] arr) {
this.s = s;
this.arr = arr;
}
#Override
public void run() {
s.sort(arr);
}
}
--- edit: answer ---
Based on comments from everyone:
No. What I'm doing is not safe as Thread.interrupt() will not suspend the thread, it'll just set it's interrupted state, which if not checked by the thread's run() implementation, is useless.
In this case the next Sorter's sort() would be called on the same array (which is still being sorted by the old "interrupted" thread), thus making things unsafe.
One option is to create a separate Process instead of a Thread. A Process can be killed.
Obviously the parameter passing isn't easy in this case as it involves some IPC.
As you may have seen from the other questions you mention, it isn't possible to reliably stop a Java thread without its cooperation, because interrupt() ony works if the thread tests for it (deliberately or inadvertently).
However, it is possible to kill a process. If you spawn each sorting algorithm in a separate process, then you can kill it forcibly.
The downside is that interacting with the process is significantly harder than interacting with a thread, since you don't have shared variables.
Without a thread's cooperation, there is no reliable and safe way to stop it. With a thread's cooperation, you can interrupt or stop a thread using the mechanism it supports. Threads just don't provide this kind of isolation ... you have to use multiple processes.
This may be a case for Thread.stop(). Do read the disclaimer in the javadoc, though, in particular:
Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait.
would it work consistently, or could there be any issues?
It would work except that you need to handle the thread interrupt correctly. thread.interrupt() will only work if the sort method supports it. I suspect that the method will not be calling Thread.sleep(), wait(), or other such methods. Therefore it needs to test to see if it has been interrupted as it does its processing:
while (!Thread.currentThread().isInterrupted()) {
// do sort stuff
}
If it doesn't do that then interrupting the thread will not stop the processing. I would certainly add another test.join(); after the interrupt to make sure that the thread finishes before you start another sort operation.