在以下Java程序中,我在HashMap中存储了3个线程,我创建了3个Th类对象,它们是从类Thread扩展的(我已经尝试过实现Runnable,但它也无效!),我想停止通过分配空值3秒后t2我无法停止它,我不想使用stop()方法,因为它已被弃用,它只有在我使用start方法启动线程时才有效,而如果我启动它则不起作用线程使用ExecutorService的execute方法
public class TestingThreads {
static HashMap<String, Thread> trds = new HashMap<>();
static Th t1 = new Th("Th1");
static Th t2 = new Th("Th2");
static Th t3 = new Th("Th3");
public TestingThreads() {
}
public static void main(String[] args) {
long ct = System.currentTimeMillis();
ExecutorService executor = Executors.newCachedThreadPool();
trds.put("t1", t1);
trds.put("t2", t2);
trds.put("t3", t3);
executor.execute(t1);
executor.execute(t2);
executor.execute(t3);
executor.shutdown();
new Thread() {
@Override
public void run() {
while (true) {
if (ct + 3000 < System.currentTimeMillis()) {
trds.put("t2", null);
trds.remove("t2");
System.out.println("Size = " + trds.size());
//I dont wanna use the stop() method as is it deprecated and it only works when I use start method to run the Thread while it is not working with execute() method of class ExecutorService
// t2.stop();
t2 = null;
break;
}
}
}
}.start();
}
}
class Th extends Thread {
String name;
Random rm = new Random();
public Th(String name) {
this.name = name;
}
@Override
public void run() {
while (!this.isInterrupted()) {
int i = rm.nextInt(500);
try {
Thread.sleep(i);
} catch (InterruptedException ex) {
}
System.out.println(name + " " + i);
}
}
}
这只是一个线程的示例..创建一个静态volatile boolean标志。
static volatile boolean RUN_THREAD_FLAG= true;
Thread yourThread= new Thread(){
@Override
public void run() {
try{
// you can add your other conditions inside while condition
// and AND it with the FLAG
//while(RUN_THREAD_FLAG && yourCondition)
while(RUN_THREAD_FLAG){
sleep(SLEEP_TIME); //OR your task
}
} catch(Exception e){
e.printStackTrace();
}
}
};
yourThread.start();
当你想要停止线程时,只需设置RUN_THREAD_FLAG = false
PS:您应该使用一些FLAG或其他方法尽可能长时间地正确结束线程。尽量不要使用任何中断方法。
您也可以尝试类似的解决方案如下: -
import java.util.HashMap; import java.util.Random;
公共类TestingThreads {
static Th t1 = new Th("Th1");
static Th t2 = new Th("Th2");
static Th t3 = new Th("Th3");
public TestingThreads() {
}
public static void main(String[] args) {
t1.start();
t2.start();
t3.start();
}
class Th扩展Thread {
String name;
Random rm = new Random();
public Th(String name) {
this.name = name;
}
@Override
public void run() {
final long ct = System.currentTimeMillis()+3000;
Thread t= Thread.currentThread();
System.out.println("Running Thread is :-"+t.getName()+" "+System.currentTimeMillis());
while (true) {
if (ct < System.currentTimeMillis()) {
try{
System.out.println("Running Thread is :-"+t.getName()+" "+System.currentTimeMillis());
t.interrupt();
break;
}
catch(Exception ie)
{
System.out.println(t.getName()+" closed");
ie.printStackTrace();
}
}
}
}
}
检查你的代码,甚至不能使用t2
停止stop
,因为t2
永远不会启动,它由executor
执行。要停止t2
,您需要直接运行t2
:(对上次编辑的代码进行了更改:如果线程在sleep
中断,并执行t2.start()
而不是executor.execute(t2)
,则设置中断标志= true)
public class TestingThreads {
static HashMap<String, Thread> trds = new HashMap<>();
static Th t1 = new Th("Th1");
static Th t2 = new Th("Th2");
static Th t3 = new Th("Th3");
public TestingThreads() {
}
public static void main(String[] args) {
long ct = System.currentTimeMillis();
ExecutorService executor = Executors.newCachedThreadPool();
trds.put("t1", t2);
trds.put("t2", t2);
trds.put("t3", t3);
executor.execute(t1);
/*executor.execute(t2);*/ t2.start();
executor.execute(t3);
executor.shutdown();
new Thread() {
@Override
public void run() {
while (true) {
if (ct + 3000 < System.currentTimeMillis()) {
trds.put("t2", null);
trds.remove("t2");
System.out.println("Size = " + trds.size());
// t2.stop();
t2.interrupt();
t2 = null;
break;
}
}
}
}.start();
}
}
class Th extends Thread {
String name;
Random rm = new Random();
public Th(String name) {
this.name = name;
}
@Override
public void run() {
while (!this.isInterrupted()) {
int i = rm.nextInt(500);
try {
Thread.sleep(i);
} catch (InterruptedException ex) {
this.interrupt(); // this line was also added
// or better use "return" as suggested by Bill K
}
System.out.println(name + " " + i);
}
}
}
您对使用t2.interrupt的更改将起作用,但您需要将线程更改为如下所示:(请注意return语句)。
@Override
public void run() {
while (!this.isInterrupted()) {
int i = rm.nextInt(500);
try {
Thread.sleep(i);
} catch (InterruptedException ex) {
return;
}
System.out.println(name + " " + i);
}
}
当sleep方法被中断时,它会抛出InterruptedException但在它执行之前清除该标志。您必须在异常中执行某些操作才能使其正常工作。另一种方式是:
boolean running=true;
@Override
public void run() {
while (running) {
int i = rm.nextInt(500);
try {
Thread.sleep(i);
} catch (InterruptedException ex) {
running=false;
}
System.out.println(name + " " + i);
}
}
请注意,由于现在只能从一个线程访问运行,因此它不必是volatile。
首先,不要扩展Thread
来实现任务(=工作)!我认为你误解了执行者框架。它已经照顾了Threads
,你不必自己创建一个!你想要做的是实现由Runnable
执行的任务(=实现Executor
)。
其次,您的任务应该对中断敏感,即通过调用interrupt()
来中断执行线程应该导致您的任务完成其工作:
public class Task implements Runnable {
public void run() {
try {
while (true) {
int i = rm.nextInt(500);
Thread.sleep(i);
System.out.println(name + " " + i);
}
} catch (InterruptedException ex) {
// restore interruption flag
Thread.currentThread.interrupt();
}
}
}
请注意,我们可以在这里使用无限循环,因为Thread.sleep
将抛出一个InterruptedException
,一旦执行Thread
被中断,它将退出循环。 (否则我们必须通过自己调用Thread.currentThread().isInterrupted
来检查中断标志)。
第三,使用ScheduledExecutorService
执行任务和取消:
ScheduledExecutorService exectuor = Executors.newScheduledThreadPool(4);
Future<?> t1f = executor.execute(new Task());
Future<?> t2f = executor.execute(new Task());
Future<?> t3f = executor.execute(new Task());
// now we can cancel tasks individually after a certain amount of time:
executor.schedule(() -> t2f.cancel(true), 3, TimeUnit.SECOND);
最后一行代码使用自Java 8以来可用的lambda表达式。如果您不想使用它们或由于某些原因无法使用它们,请再次使用普通的Runnable
:
executor.schedule(new Runnable() {
public void run() { t2f.cancel(true); }
}, 3, TimeUnit.SECOND);
using a boolean variable:
package com.Exception.Demos;
public class MyRunnable implements Runnable {
boolean continueThread=true;
@Override
public void run() {
// TODO Auto-generated method stub
int i=0;
while(true){
if(continueThread){
try{
System.out.println(i++);
Thread.sleep(1000);
System.out.println("press enter to stop "+Thread.currentThread().getName());
}catch(InterruptedException exception){
exception.printStackTrace();
}
}
else{
System.out.println(Thread.currentThread().getName()+"Ended");
break;
}
}
}
}
package com.Exception.Demos;
import java.io.IOException;
public class TerminatingAThread {
public static void main(String[] args) throws IOException {
MyRunnable myRunnable=new MyRunnable();
Thread thread=new Thread(myRunnable,"Thread1");
thread.start();
System.out.println(Thread.currentThread().getName()+"thread waiting for user to press enter");
System.in.read();
myRunnable.continueThread=false;
System.out.println(Thread.currentThread().getName()+"thread ended");
}
}
这里有两个主要课程:
现在了解详情:
线程实现了Runnable。当您创建Th扩展Thread的实例并将它们传递给ExecutorService时,执行程序不会在传入的线程上运行任务。它只知道你给了它一个Runnable,它继续在其一个工作线程上执行Runnable。
这就是为什么在使用ExecutorService时没有看到设置中断标志的原因。它还解释了为什么它在您启动自己的线程时有效。你正在寻找中断
this.isInterrupted()
其中this
是您传入的线程,但它是池的工作线程,而不是Th实例,它会在其上调用中断。将支票更改为
Thread.currentThread().isInterrupted()
捕获InterruptedException时,还应设置中断标志。当sleep方法抛出InterruptedException时,它会清除该标志(因此在下一个while循环迭代中,isInterrupted返回false)。如上所述,您应该在当前线程上调用interrupt,而不是在this
上调用。
等待执行程序完成的线程是不必要的(忙碌的等待它正在做的不好),你可以调用awaitTermination。
使用shutdown也不起作用,因为这些任务永远不会自行退出,它们必须被中断。礼貌地等待当前的任务完成,这将永远不会发生;你需要shutdownNow才能中断任务。
这是一个更简单的程序来执行相同的操作,它提交3个任务并让它们在关闭之前执行3秒。注意所有我不需要做的事情,我不必在散列图中松散任务,我不需要看门狗线程来等待执行程序终止。
import java.util.*;
import java.util.concurrent.*;
public class TestThreads {
public static void main(String... args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Th("t1"));
executor.execute(new Th("t2"));
executor.execute(new Th("t3"));
Thread.sleep(3000L);
executor.shutdownNow();
executor.awaitTermination(10000L, TimeUnit.MILLISECONDS);
System.out.println("executor terminated=" + executor.isTerminated());
}
}
class Th implements Runnable {
String name;
Random rm = new Random();
public Th(String name) {
this.name = name;
}
@Override public void run() {
while (!Thread.currentThread().isInterrupted()) {
int i = rm.nextInt(500);
try {
Thread.sleep(i);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(name + " " + i);
}
}
}