java线程中stop(),在Java中使用Thread#stop()杀死正在运行的线程是否可以接受?

Regrettably there is no way to specify a timeout when using a regular expression on a String in Java. So if you have no strict control over what patterns get applied to which input, you might end up having threads that consume a lot of CPU while endlessly trying to match (not so well designed) patterns to (malicious?) input.

I'm aware of the reasons why Thread#stop() is deprecated (see http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html). They are centered around objects that might get damaged in case of ThreadDeath exceptions, and which then pollute your running JVM environment and can lead to subtle errors.

My question to anyone who has deeper insight than me into the workings of the JVM is this: If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?

I created a rather defensive solution to be able to process regular expression matching with a timeout. I would be glad for any comment or remark, especially on problems that this approach can cause despite my efforts to avoid them.

Thanks!

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 thread = createSafeRegularExpressionMatchingThread();

Boolean result = tryToGetResultFromThreadWithTimeout(thread);

return result;

}

private CallableThread createSafeRegularExpressionMatchingThread() {

final String stringToMatchForUseInThread = new String(stringToMatch);

final String regularExpressionForUseInThread = new String(regularExpression);

Callable callable = createRegularExpressionMatchingCallable(stringToMatchForUseInThread,

regularExpressionForUseInThread);

CallableThread thread = new CallableThread(callable);

return thread;

}

private Callable createRegularExpressionMatchingCallable(final String stringToMatchForUseInThread,

final String regularExpressionForUseInThread) {

Callable callable = new Callable() {

public Boolean call() throws Exception {

return Boolean.valueOf(stringToMatchForUseInThread.matches(regularExpressionForUseInThread));

}

};

return callable;

}

private Boolean tryToGetResultFromThreadWithTimeout(CallableThread thread) {

startThreadAndApplyTimeout(thread);

Boolean result = processThreadResult(thread);

return result;

}

private void startThreadAndApplyTimeout(CallableThread thread) {

thread.start();

try {

thread.join(timeoutMillis);

} catch (InterruptedException e) {

throwRuntimeException("Interrupt", e);

}

}

private Boolean processThreadResult(CallableThread 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 thread) {

thread.stop();

}

private static class CallableThread extends Thread {

private final Callable callable;

private V result = null;

private Exception exception = null;

public CallableThread(Callable 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;

}

}

}

EDIT:

Thanks to dawce who pointed me to this solution I have been able to solve my original problem without the need for additional threads. I have posted the code there. Thanks to all who have responded.

解决方案

You can use Thread.stop() if you determine its the only solution available to you. You may need to shutdown and restart your applicaton to ensure its in a good state.

Note: a Thread can capture and ignore ThreadDeath so stop isn't guarenteed to stop all threads.

An alternative way to stop a thread is to run it in a different process. This can be killed as required. This can still leave resources in an incosistent state (like lock files) but it is less likely and easier to control.

The best solution of course is to fix the code so it doesn't do this in the first place and respects Thread.interrupt() instead.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值