用Java清理线程

bad*_*oit 9 java concurrency multithreading

我有一个Java方法,它对输入集执行两次计算:估计和准确的答案.估计总是可以廉价地在可靠的时间内计算出来.准确的答案有时可以在可接受的时间内计算,有时不会(不知道先验......必须试着看).

我想要设置的是一些框架,如果准确答案花费太长时间(固定超时),则使用预先计算的估计.我想我会使用一个线程.主要的复杂因素是计算准确答案的代码依赖于外部库,因此我无法"注入"中断支持.

针对此问题的独立测试用例就在这里,展示了我的问题:

package test;

import java.util.Random;

public class InterruptableProcess {
    public static final int TIMEOUT = 1000;

    public static void main(String[] args){
        for(int i=0; i<10; i++){
            getAnswer();
        }
    }

    public static double getAnswer(){
        long b4 = System.currentTimeMillis();
        // have an estimate pre-computed
        double estimate = Math.random();

        //try to get accurate answer
        //can take a long time
        //if longer than TIMEOUT, use estimate instead
        AccurateAnswerThread t = new AccurateAnswerThread();
        t.start();

        try{
            t.join(TIMEOUT);
        } catch(InterruptedException ie){
            ;
        }

        if(!t.isFinished()){
            System.err.println("Returning estimate: "+estimate+" in "+(System.currentTimeMillis()-b4)+" ms");
            return estimate;
        } else{
            System.err.println("Returning accurate answer: "+t.getAccurateAnswer()+" in "+(System.currentTimeMillis()-b4)+" ms");
            return t.getAccurateAnswer();
        }

    }

    public static class AccurateAnswerThread extends Thread{
        private boolean finished = false;
        private double answer = -1;

        public void run(){
            //call to external, non-modifiable code
            answer = accurateAnswer();
            finished = true;
        }

        public boolean isFinished(){
            return finished;
        }

        public double getAccurateAnswer(){
            return answer;
        }

        // not modifiable, emulate an expensive call
        // in practice, from an external library
        private double accurateAnswer(){
            Random r = new Random();
            long b4 = System.currentTimeMillis();
            long wait = r.nextInt(TIMEOUT*2);

            //don't want to use .wait() since
            //external code doesn't support interruption
            while(b4+wait>System.currentTimeMillis()){
                ;
            }
            return Math.random();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这工作正常输出...

Returning estimate: 0.21007465651836377 in 1002 ms
Returning estimate: 0.5303547292361411 in 1001 ms
Returning accurate answer: 0.008838428149438915 in 355 ms
Returning estimate: 0.7981717302567681 in 1001 ms
Returning estimate: 0.9207406241557682 in 1000 ms
Returning accurate answer: 0.0893839926072787 in 175 ms
Returning estimate: 0.7310211480220586 in 1000 ms
Returning accurate answer: 0.7296754467596422 in 530 ms
Returning estimate: 0.5880164300851529 in 1000 ms
Returning estimate: 0.38605296260291233 in 1000 ms
Run Code Online (Sandbox Code Playgroud)

但是,我有一个非常大的输入集(大约数十亿项)来运行我的分析,我不确定如何清理未完成的线程(我不希望它们在背景).

我知道破坏线程的各种方法都有很好的理由被弃用.我也知道停止线程的典型方法是使用中断.但是,在这种情况下,我没有看到我可以使用中断,因为该run()方法将单个调用传递给外部库.

在这种情况下如何杀死/清理线程?

Mar*_*nik 2

如果你对外部库足够了解,比如:

  1. 从不获取任何锁;
  2. 从不打开任何文件/网络连接;
  3. 不涉及任何 I/O,甚至不涉及日志记录;

那么使用它可能是安全的。Thread#stop您可以尝试并进行广泛的压力测试。任何资源泄漏都会很快显现出来。