杀死线程或异步任务

时间:2018-06-11 05:40:53

标签: java multithreading kotlin

让我们说我使用了IBM创建的jar。 让我们说这个Jar有我需要的功能,但最终是这样构建的:

 while (true) {
     System.out.println(1)
 }

(当然它并不仅仅是打印1,但是对于这个例子,让我们说它是) 所以,我调用了使用future在另一个线程中执行它的函数。我怎样才能完全杀死运行此代码的线程?或者,我怎样才能杀死运行代码的Kotlin中的异步任务。

Kotlin或Java中的解决方案会很棒, 提前谢谢!

编辑:

我发现,如果这是一个主题,我可以Thread#stop()它真的让它停止。但遗憾的是,构造函数多次抛出异常会导致JVM从内存中删除该类,导致下次实例化该类时出现NoClassDefFoundError

3 个答案:

答案 0 :(得分:0)

如果你能抓住它的线程,你应该能够杀死它,只要它在内部做某种阻塞功能。

class OtherFunction implements Runnable {

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // We assume the thread will exit when interrupted.
                System.out.println("Bye!!");
                return;
            }
            System.out.println("Hello");
        }
    }
}


class Killable implements Runnable {
    final Runnable target;
    private Thread itsThread;

    Killable(Runnable target) {
        this.target = target;
    }

    @Override
    public void run() {
        // Catch the thread id of the target.
        itsThread = Thread.currentThread();
        // Launch it.
        target.run();
    }

    public void kill() {
        // Give it a good kick.
        itsThread.interrupt();
    }
}

public void test() throws InterruptedException {
    OtherFunction theFunction = new OtherFunction();
    Killable killableVersion = new Killable(theFunction);
    new Thread(killableVersion).start();
    // Wait for a few seconds.
    Thread.sleep(10000);
    // Kill it.
    killableVersion.kill();
}

答案 1 :(得分:0)

似乎Thread#stop()解决了我的问题。我知道它被弃用了,catch(Throwable t)可以阻止它,但至少它对我有用。

顺便说一下,为了从执行程序中获取线程,我使用了AtomicReference<Thread>并在回调中设置了它。

答案 2 :(得分:0)

Thread#stop()已被弃用,因为其本质上不安全&#39;如果可能的话应该避免。

它是不稳定和腐败的根源,无论如何都可能失败!

它实际上导致在目标线程中抛出ThreadDeath异常。 它弹出的任何代码的作者都不太可能预料到这种结果。 对象可能处于不一致状态,外部资源可能被保留并被泄露,文件可能未完整写入。

有一些方法可以处理意外错误,但在实践中,大多数代码都是在假设它知道可能抛出哪些异常而不是预期会出现这样的“惊喜”的情况下编写的。

鉴于ThreadDeathThrowable任何catch(Throwable t)将会再次捕获它,除非在线程可能执行的每一段代码中都非常谨慎(不切实际)ThreadDeath可能只是被吸收而不是结束线程。

处理此问题的正确方法是声明一个原子变量(通常作为代表任务的Runnable的一部分。

AtomicBoolean stopThread=new AtomicBoolean(false);

然后将循环写为:

 while (!stopThread.get()) {
     System.out.println(1);
 }

并提供一种方法:

public void stopThread(){
    stopThread.set(true);
} 

或者,您可以使用interrupt()并检查interrupted()。这些是Thread类中提供的更清晰的方法。 interrupted()具有在调用时清除标志的行为。这并不总是有用,虽然可以通过Thread.currentThread().isInterrupted()检查标记,但检查标记会清除标记。行为可能是无益的,也会受到stop()的一些问题的困扰,因为它可能导致令人惊讶的问题。在其他代码从未预料到的点上抛出异常。正确的方法是使用自己的旗帜,并完全控制过程决定退出的位置。

选择。

另请参阅:Java Thread Primitive Deprecation

想知道为何点击“取消”&#39;在一些并发过程中,你经常被迫等待多年才能做出回应? 这就是为什么。任务需要达到一个明确定义的点,并进行必要的清理,以明确定义的方式终止。

认为Thread#stop()就像骑自行车一样阻止骑车人。这里的方法向他们挥动一个红旗,然后他们就像他们安全的那样迅速停下来。

Thread#stop()永远不应该是Java,你永远不应该使用它。 你在开发和小型系统中侥幸成功。它会在大型生产环境中造成严重破坏。 它不仅被弃用,因为不推荐使用&#39;它本质上是不安全的&#39;不要使用它。 它已被弃用了多年,令人失望的是一些删除日期&#39;从来没有做过广告宣传。

以下是使用Thread#stop()interrupt()的示例,具体取决于您是否选择危险。

import java.lang.System;
import java.lang.Thread;

class Ideone
{

    private static boolean beDangerous=true;//Indicates if we're going to use the Thread#stop().... 

    //This main method uses either stop() or interrupt() depending on the option.
    public static void main (String[] args) throws java.lang.Exception
    {

        PrimeFactor factor=new PrimeFactor();
        try{
    for(int i=1;i<30;++i){
        Thread thrd=new Thread(new Primer(factor));
        thrd.start();

        Thread.sleep(10);//Represents some concurrent processing...

        if(beDangerous){
            thrd.stop();
        }else{
            thrd.interrupt();
        }
        thrd.join();
        if(!factor.check()){
            System.out.println("Oops at "+i);
        }
    }
        }catch(Throwable t){
            System.out.println(t);
        }
    }

    //This class just hammers the PrimeFactor object until interrupt()ed (or stop()ed).
    private static class Primer implements Runnable {

        private PrimeFactor factor;

        public Primer(PrimeFactor ifactor){
            factor=ifactor;
        }


        public void run(){
            int i=1;
            while(!Thread.interrupted()){   
                factor.set(i++);    
        }
           }
    }

    //Don't worry about this bit too much.
    //It's a class that does a non-trivial calculation and that's all we need to know.
    //"You're not expected to understand this". If you don't get the joke, Google it.

    //This class calculates the largest prime factor of some given number.
    //Here it represents a class that ensures internal consistency using synchronized.
    //But if we use Thread#stop() this apprently thread-safe class will be broken.
    private static class PrimeFactor {
        private long num;
        private long prime;

        public static long getFactor(long num){
            if(num<=1){
               return num;
            }
            long temp=num;
            long factor=2;
            for(int i=2;temp!=1;++i){
                if(temp%i==0){
                    factor=i;
                    do{
                        temp=temp/i;
                    }while(temp%i==0);
                }   
            }
            return factor;
        } 

        public synchronized void set(long value){
            num=value;
            prime=getFactor(value);
        }

        public synchronized boolean check(){
            return prime==getFactor(num);
        }
    }   
}

典型的部分输出:

Oops at 1
Oops at 2
Oops at 3
Oops at 6
Oops at 8

请注意,PrimeFactor类可以描述为线程安全的。它的所有方法都是synchronized。想象一下它在一些图书馆里。期望&#34;线程安全&#34;是不现实的。表示Thread#stop() - 安全,唯一的方法就是打扰。在try-catch(ThreadDeath tde)块中调用它不会解决任何问题。在受到伤害之前,伤害将会下降。

请勿让自己相信将set()更改为以下内容可以解决问题:

public synchronized void set(long value){
    long temp=getFactor(value);
    num=value;
    prime=temp;
}

首先,ThreadDeath例外可能会在分配期间抛出,所以这样做可能会缩短竞争条件的几率。它没有被否定。永远不要做出这样的可能性&#34;关于竞争条件的争论。程序称方法数十亿次,因此定期出现数十亿次单击。

要使用Thread#stop(),你基本上不会使用任何库对象,包括java.*,并跳过箍来处理代码中的任何地方ThreadDeath,并且几乎肯定最终都会失败。