一个好的软件线程通常都是可控制的,开发者不但可以利用多线程来提升软件的效率,以可以HOLD住线程,可以销毁线程,防止线程泄漏。
什么是JAVA的线程停止?
前段时间,我还自认为线程的停止,指的是线程的销毁。如果我停止一个线程,那么这个线程将会被销毁,至于如何销毁,那都是JVM应该考虑的事情,我只需调用对应 的API(比如Thread.interrupt(), Thread.stop(), Thread.destroy())。
后来发现不是那么一回事,JAVA中线程的停止是交给开发者来维护的,不是简简单单的调用了一个接口,线程就不复存在了,且线程所用的资源也都被释放了,如果真是这样,那JVM也真是太强大了。
好的线程停止,是通过响应中断方法来实现的。
那么问题来了,谁有资格去停止线程?
线程的创建者(或者任务的提交者)应该负责来停止线程。当业务上需要中断一批任务时,把消息发送给线程的创建者或者任务的提交者(根据信息专家模式),因为他们持有线程的信息。
一个好的线程写法,应该是提交和任务相分离。如果代码中出现这样的语句:
new Thread(Runnable).start()
这是一个糟糕的写法,因为这意味着,创建的线程永远无法被人工的终止,当大量创建这样的线程时,这些线程就相当于无政府主义者,不受约束,一旦产生,将会自生自灭。而且这样 的线程不容易修改,假如工程中有一百个上述代码片段,现在任务要变成同步执行(原先的写法肯定是并发执行),如何?这样改动可能要该100处,这对于维护者或者重构者来说简直就是灾难。
好的写法应该是任务的提交和创建相分离(上面是典型的创建和提交混合在一起了)。
比如如下代码:
public class MyThreadSubmitter implements Executor {
@Override
public void execute(Runnable command) {
Thread thread = new Thread(command);
thread.start();
}
}
当想同步执行时,换一个方式就可以了,只需要改动一处,代码如下:
public class MyThreadSubmitter implements Executor {
@Override
public void execute(Runnable command) {
command.run();
}
}
上面阐述了任务的提交和创建相分离,回归老问题:如何终止一个线程?上面已经简要回答了下:即由程序员来维护线程,在程序员写代码的时候,就要考虑到线程终止,通过响应线程中断信号来实现。而不是交由JVM,任凭JVM来销毁,这样是不符合业务逻辑的。
那么如何来编写响应中断式的线程?这个用一个例子来说明。
public class Task implements Runnable {
@Override
public void run() {
try {
boolean isInterrupt = false;
while (!(isInterrupt = Thread.interrupted())) {
//处理业务逻辑
}
if (isInterrupt) {//相应线程中断
}
} catch (Throwable e) {//防止线程泄漏
e.printStackTrace();
} finally{
//释放资源
}
}
}
如何提交呢?
public class TaskSubmiter {
private static ExecutorService executor = Executors.newCachedThreadPool();
private List<Future<?>> futures = new ArrayList<Future<?>>();
public void sumbit(Task task){
futures.add(executor.submit(task));
}
public void stop(){
for (int i = 0; i < futures.size(); i++) {
Future<?> future = futures.get(i);
if (!future.isCancelled()) {
future.cancel(true);
}
}
futures.clear();
}
}
因为TaskSubmiter是任务的提交者,故TaskSubmiter持有线程的上线文信息,发送停止指令,应发送到该类。stop接口提现了线程的停止。以上就是一个通过响应中断来实现线程停止的简单模型。