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

问题描述 投票:1回答:7

在以下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);
        }
    }
}
java multithreading
7个回答
1
投票

这只是一个线程的示例..创建一个静态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或其他方法尽可能长时间地正确结束线程。尽量不要使用任何中断方法。


0
投票

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

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

        }
    }
}

}


0
投票

检查你的代码,甚至不能使用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);
        }
    }
}

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

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


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

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

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)。如上所述,您应该在当前线程上调用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);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.