微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Java中可以接受使用Thread#stop()来杀死正在运行的线程吗?

遗憾的是,在 Java中对String使用正则表达式时无法指定超时.因此,如果您没有严格控制哪些模式应用于哪个输入,您可能最终会拥有消耗大量cpu的线程,同时无休止地尝试将(不那么精心设计的)模式与(恶意?)输入匹配.

我知道为什么弃用Thread#stop()的原因(见http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html).它们以可能在ThreadDeath异常情况下被损坏的对象为中心,然后污染正在运行的JVM环境并可能导致细微的错误.

我对这个对JVM工作有更深入了解的人的问题是:如果需要停止的线程没有任何(明显的)监视器或对程序其余部分使用的对象的引用,那么可以使用Thread#stop()吗?

我创建了一个相当防御的解决方案,能够处理与超时匹配的正则表达式.我会很高兴任何评论评论,尤其是尽管我努力避免它们,这种方法可能导致的问题.

谢谢!

import java.util.concurrent.Callable;

public class SafeRegularExpressionMatcher {

    // demonstrates behavior for regular expression running into catastrophic backtracking for given input
    public static void main(String[] args) {
        SafeRegularExpressionMatcher matcher = new SafeRegularExpressionMatcher(
                "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","(x+x+)+y",2000);
        System.out.println(matcher.matches());
    }

    final String stringToMatch;

    final String regularExpression;

    final int timeoutMillis;

    public SafeRegularExpressionMatcher(String stringToMatch,String regularExpression,int timeoutMillis) {
        this.stringToMatch = stringToMatch;
        this.regularExpression = regularExpression;
        this.timeoutMillis = timeoutMillis;
    }

    public Boolean matches() {
        CallableThread<Boolean> thread = createSafeRegularExpressionMatchingThread();
        Boolean result = tryToGetResultFromThreadWithTimeout(thread);
        return result;
    }

    private CallableThread<Boolean> createSafeRegularExpressionMatchingThread() {
        final String stringToMatchForUseInThread = new String(stringToMatch);
        final String regularExpressionForUseInThread = new String(regularExpression);
        Callable<Boolean> callable = createRegularExpressionMatchingCallable(stringToMatchForUseInThread,regularExpressionForUseInThread);
        CallableThread<Boolean> thread = new CallableThread<Boolean>(callable);
        return thread;
    }

    private Callable<Boolean> createRegularExpressionMatchingCallable(final String stringToMatchForUseInThread,final String regularExpressionForUseInThread) {
        Callable<Boolean> callable = new Callable<Boolean>() {
            public Boolean call() throws Exception {
                return Boolean.valueOf(stringToMatchForUseInThread.matches(regularExpressionForUseInThread));
            }
        };
        return callable;
    }

    private Boolean tryToGetResultFromThreadWithTimeout(CallableThread<Boolean> thread) {
        startThreadAndApplyTimeout(thread);
        Boolean result = processthreadResult(thread);
        return result;
    }

    private void startThreadAndApplyTimeout(CallableThread<Boolean> thread) {
        thread.start();
        try {
            thread.join(timeoutMillis);
        } catch (InterruptedException e) {
            throwRuntimeException("Interrupt",e);
        }
    }

    private Boolean processthreadResult(CallableThread<Boolean> thread) {
        Boolean result = null;
        if (thread.isAlive()) {
            killThread(thread); // do not use anything from the thread anymore,objects may be damaged!
            throwRuntimeException("Timeout",null);
        } else {
            Exception exceptionOccurredInThread = thread.getException();
            if (exceptionOccurredInThread != null) {
                throwRuntimeException("Exception",exceptionOccurredInThread);
            } else {
                result = thread.getResult();
            }
        }
        return result;
    }

    private void throwRuntimeException(String situation,Exception e) {
        throw new RuntimeException(situation + " occured while applying pattern /" + regularExpression + "/ to input '"
                + stringToMatch + " after " + timeoutMillis + "ms!",e);
    }

    /**
     * This method uses {@link Thread#stop()} to kill a thread that is running wild. Although it is ackNowledged that
     * {@link Thread#stop()} is inherently unsafe,the assumption is that the thread to kill does not hold any monitors on or
     * even references to objects referenced by the rest of the JVM,so it is acceptable to do this.
     * 
     * After calling this method nothing from the thread should be used anymore!
     * 
     * @param thread Thread to stop
     */
    @SuppressWarnings("deprecation")
    private static void killThread(CallableThread<Boolean> thread) {
        thread.stop();
    }

    private static class CallableThread<V> extends Thread {

        private final Callable<V> callable;

        private V result = null;

        private Exception exception = null;

        public CallableThread(Callable<V> callable) {
            this.callable = callable;
        }

        @Override
        public void run() {
            try {
                V result = compute();
                setResult(result);
            } catch (Exception e) {
                exception = e;
            } catch (ThreadDeath e) {
                cleanup();
            }
        }

        private V compute() throws Exception {
            return callable.call();
        }

        private synchronized void cleanup() {
            result = null;
        }

        private synchronized void setResult(V result) {
            this.result = result;
        }

        public synchronized V getResult() {
            return result;
        }

        public synchronized Exception getException() {
            return exception;
        }

    }

}

编辑:

感谢dawce指出我this solution我已经能够解决我原来的问题,而无需额外的线程.我在那里发布了代码.感谢所有回复的人.

解决方法

如果确定它是唯一可用的解决方案,则可以使用Thread.stop().您可能需要关闭并重新启动应用程序以确保其处于良好状态.

注意:一个线程可以捕获并忽略ThreadDeath,因此不保证停止所有线程.

停止线程的另一种方法是在不同的进程中运行它.这可以根据需要杀死.这仍然可以使资源处于不稳定状态(如锁定文件),但它不太可能且更容易控制.

当然,最好的解决方案是修复代码,使其首先不执行此操作,而是尊重Thread.interrupt().

原文地址:https://www.jb51.cc/java/124153.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐