What the right way to interrupt executor's thread?
I've got this:
Thread class with name Worker with method:
public void run() {
while(!(Thread.currentThread().isInterrupted()){
System.out.println("work " + Thread.currentThread().getName() + ":" + Thread.currentThread().isInterrupted());
}
}
And main class with:
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
Worker worker = new Worker();
executorService.execute(worker);
I try to call worker.interrupt(); or executorService.shutdownNow(); but my thread goes on and isInterrupted() is false.
Can you post all the relevant code? Based on the information you have given, I can't reproduce the behaviour you describe. See below a SSCCE that works as expected - output:
work pool-1-thread-1:false
work pool-1-thread-1:false
work pool-1-thread-1:false
....
Thread has been interrupted
Code:
public class Test {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Worker worker = new Worker();
executorService.execute(worker);
executorService.shutdownNow();
}
public static class Worker extends Thread {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("work " + Thread.currentThread().getName() + ":" + Thread.currentThread().isInterrupted());
}
System.out.println("Thread has been interrupted");
}
}
}
Related
This question already has answers here:
How do you kill a Thread in Java?
(17 answers)
Closed 2 years ago.
I'm working with threads in Java 8 and I'm using the next code:
Runnable runnable = () -> {
LOGGER.info(....);
someCode
};
Thread thread = new Thread(runnable);
thread.start();
My doubt is how can I stop or interrupt the thread or it will be stopped with itself?
Any ideas?
Thread will be automatically cleaned up after the public void run() method exits (implementation of which is your lambda expression), and there is no safe way you can explicitly tell the thread to stop.
However, you can simulate the stop instruction, if you'll either introduce a shared flag variable, or simply create your thread by extending the Thread class, instead of passing the Runnable to the Thread constructor. This way you can incorporate a flag field:
class MyThread extends Thread {
private boolean isAlive;
public MyThread() {
this.isAlive = true;
}
public synchronized void setAlive(boolean status) {
if (status == true) {
return;
}
this.isAlive = status;
System.out.println("Stopping " + Thread.currentThread().getName() + "thread..");
System.out.println(Thread.currentThread().getName() + " has been stopped.");
}
#Override
public void run() {
int i = 0;
while (isAlive) {
System.out.println(i + " invocation in the " + Thread.currentThread().getName() + "thread.");
++i;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
}
public class MainClass {
public static void main(String[] args) throws Exception {
MyThread thread = new MyThread();
thread.start(); //instruction #1
Thread.sleep(2000);
System.out.println("In the main thread...");
Thread.sleep(2000);
System.out.println("In the main thread...");
thread.setAlive(false); //after this, you'll see, that the Thread running after instruction #1 doesn't exist anymore
Thread.sleep(2000);
System.out.println("In the main thread...");
Thread.sleep(2000);
System.out.println("In the main thread...");
}
}
join() is supposed to make main function wait until all the threads complete execution, but main is printing completed before Thread-1 and Thread-2 completes execution.
I am unable to find error in the code. where's the mistake?
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
}
public void run() {
System.out.println("Thread " + threadName + " exiting.");
}
public void start() {
if (t == null) {
t = new Thread (this, threadName);
t.start();
}
}
}
public class Problem2 {
public static void main(String[] args) {
ThreadDemo T1 = new ThreadDemo("Thread-1");
ThreadDemo T2 = new ThreadDemo("Thread-2");
T1.start();
T2.start();
try {
T1.join();
T2.join();
} catch (InterruptedException e) {
System.out.println("ERROR!");
}
System.out.println("completed");
}
}
Output
completed
Thread Thread-2 exiting.
Thread Thread-1 exiting.
You're joining on the ThreadDemo instances. But you're not running these instances as threads. Your overridden start method creates and starts another Thread.
Your code is extremely convoluted. You use both inheritance and delegation, and you override methods and break their contract: start() is supposed to start this as a thread, not create and start another thread.
Here's what it should look like:
class ThreadDemo implements Runnable {
private String threadName;
ThreadDemo(String name) {
this.threadName = name;
}
#Override
public void run() {
System.out.println("Thread " + threadName + " exiting.");
}
}
public class Problem2 {
public static void main(String[] args) {
ThreadDemo runnable1 = new ThreadDemo("Thread-1");
ThreadDemo runnable2 = new ThreadDemo("Thread-2");
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
System.out.println("ERROR!");
}
System.out.println("completed");
}
}
What will happen if we do entire Thread functionality in start method instead of run method?Below code runs in same way as it would have run if I added code in run method..
public class RunMethodTest extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Abc abc=new Abc();
abc.start();
}
}
class Abc extends Thread
{
#Override
public synchronized void start() {
super.start();
for(int i=0;i<10;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread" + " " + i);
}
}
}
Test it: have your code tell you which thread it is being called in by
Getting the current thread via Thread.currentThread()
And then getting the current thread's id and name via getId() and getName()
public class ThreadTest {
public static void main(String[] args) {
Thread currentThread = Thread.currentThread();
System.out.printf("Main, Which Thread: %s, %d%n",
currentThread.getName(),
currentThread.getId());
Abc abc = new Abc();
abc.start();
}
}
class Abc extends Thread {
#Override
public synchronized void start() {
super.start();
Thread currentThread = Thread.currentThread();
System.out.printf("Start, Which Thread: %s, %d%n",
currentThread.getName(),
currentThread.getId());
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread" + " " + i);
}
}
#Override
public void run() {
super.run();
Thread currentThread = Thread.currentThread();
System.out.printf("Run, Which Thread: %s, %d%n",
currentThread.getName(),
currentThread.getId());
}
}
For me this returns:
Main, Which Thread: main, 1
Start, Which Thread: main, 1
Run, Which Thread: Thread-0, 9
Thread 0
Thread 1
Thread 2
Thread 3
....
Which proves that your Abc's start method is (as expected) being called in the same thread as the calling code and not in a new thread, and that only code within the run() method is being called within a new thread. As has been noted above though, you almost never need to or want to extend Thread but rather implement Runnable or Callable.
I've done a simple test, and code as below :
public class InterruptTest
{
public static class MyTask implements Runnable {
#Override
public void run() {
System.out.println("before sleep " + Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread());
Thread.currentThread().interrupt();
System.out.println("after sleep " + Thread.currentThread().isInterrupted());
}
}
public static void main(String[] str)
{
ExecutorService service = Executors.newFixedThreadPool(1);
// MyTask task1 = new MyTask();
Future<?> future1 = service.submit(new InterruptTest.MyTask());
Future<?> future2 = service.submit(new InterruptTest.MyTask());
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
System.out.println("interrupted;");
}
}
}
And the output is :
before sleep false
Thread[pool-1-thread-1,5,main]
after sleep true
**before sleep false** // line 4
Thread[pool-1-thread-1,5,main]
after sleep true
why line 4 still output false ? not true ? Cause there is only one thread in current pool, and it should have been interrupted in the first task, why it's still available (not interrupted) when the second task runs ?
Thanks in advance!
Another question is I modify the run function as below :
public static class MyTask implements Runnable {
#Override
public void run() {
System.out.println("before sleep " + Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread());
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
System.out.println("interrupted;");
System.out.println("after sleep " + Thread.currentThread().isInterrupted());
System.out.println(Thread.currentThread());
}
}
}
And the output of one task is :
before sleep false
Thread[pool-1-thread-1,5,main]
interrupted;
after sleep false
The task should be waked up from sleep by thread.interrupt. But when I use Thread.currentThread().isInterrupted() to check it, it still return false.
Will sleep() eat the interrupt state ??
Looking at the source code of ThreadPoolExecutor, there is a private method called clearInterruptsForTaskRun documented as:
Ensures that unless the pool is stopping, the current thread does not have its interrupt set
I have following sample created to mimic the situation i am encountering related to ExecutionService shutdown process. It seems that it terminates only one thread out of 3 something... and i get error messages on tomcat server.
public class Test {
static final ExecutorService threadExecutor = Executors.newCachedThreadPool();
static Runnable getTask(final String name) {
return new Thread() {
#Override
public void run() {
this.setName("Thread-" + name);
while (true) {
try {
System.out.println(name + " running...[" + this.getName() + "]");
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("InterruptedException..." + this.getName());
throw new Exception(e);
}
}
}
};
}
public static void main(String... strings) {
threadExecutor.submit(getTask("Task-1"));
threadExecutor.submit(getTask("Task-2"));
threadExecutor.submit(getTask("Task-3"));
//--
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
ThreadPoolExecutor tpe = (ThreadPoolExecutor) threadExecutor;
System.out.println("Active Threads=====>" + tpe.getActiveCount());
tpe.shutdown();
try {
if (!threadExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
System.out.println("Executor did not terminate in the specified time.");
List<Runnable> droppedTasks = tpe.shutdownNow();
System.out.println("Shutdown thread pool forecibly. " + droppedTasks.size() + " tasks will not be executed.");
}
System.out.println("Active Threads=====>" + tpe.getActiveCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
shutdown() initiates the shutdown process within the thread pool but allows current running tasks to finish. In your example the task does not finish because of while(true).
shutdownNow() initiates the shutdown and also interrupts the currently running threads. But again your task is handling that interrupted exception and running the while(true) loop.
I think you can simply share a common boolean between your tasks and caller code from where you are calling the threadPoolExecuror.shutdown(). Use that boolean in task instead of while(true).