如何在不使用stop方法的情况下停止线程?

时间:2014-07-11 03:46:21

标签: java multithreading

在以下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);
        }
    }
}

7 个答案:

答案 0 :(得分:1)

这只是一个线程的一个例子.. 创建一个静态volatile boolean flag。

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或其他方法尽可能正确地结束线程。尽量不要使用任何中断方法。

答案 1 :(得分:0)

检查您的代码,甚至无法使用t2停止stop,因为t2永远不会启动,它由executor执行。要停止t2,您需要直接运行t2 :(对上次编辑的代码进行了更改:如果线程在sleep中断,并执行{{},则设置中断标志= true 1}}代替t2.start()

executor.execute(t2)

答案 2 :(得分:0)

您也可以尝试以下类似的解决方案: -

import java.util.HashMap; import java.util.Random;

public class 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();
            }

        }
    }
}

}

答案 3 :(得分:0)

您使用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);
    }
}

请注意,由于现在只能从一个线程访问运行,因此它不必是易失性的。

答案 4 :(得分:0)

首先,不要扩展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);

答案 5 :(得分:0)

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");
}
}

答案 6 :(得分:0)

这里有两个主要的教训:

  • 不要扩展Thread,它只会造成混淆的机会。 (即使您不使用执行程序,将要执行的逻辑与执行任务的方式分开也会提高清晰度。)

  • 线程中断是取消任务以及如何在java.util.concurrent中关闭执行程序,你必须理解它才能有效地使用执行程序。

现在了解详情:

线程实现Runnable。当您创建Th扩展Thread的实例并将它们传递给ExecutorService时,执行程序不会在传入的线程上运行任务。它只知道你给了它一个Runnable,它继续在其一个工作线程上执行Runnable。

这就是为什么在使用ExecutorService时没有看到设置中断标志的原因。它还解释了为什么它在您启动自己的线程时有效。你正在寻找中断

this.isInterrupted()

其中this是您传入的线程,但它是池的工作线程,而不是Th实例,它会在其上调用中断。将支票更改为

Thread.currentThread().isInterrupted()

当您捕获InterruptedException时,还应设置中断标志。当sleep方法抛出InterruptedException时,它会清除该标志(因此在下一个while循环迭代中,isInterrupted返回false)。如上所述,您应该在当前线程上调用中断,而不是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);
        }
    }
}