回想当年刚开始做Java开发的时候,如何停止线程运行可是难倒了一批人,停止线程的方法众说纷纭:

1. 调用Thread.stop() :

Thread thread = new Thread(){
@Override
public void run() {
for (int i=0; i < 999 && !isCanceled; i++) {
System.out.println("哈哈,我还没死...");
}
}
};
thread.start();
// kill you now
thread.stop();

点评: 不用多说,直接拉出去斩了

2. 线程外面定义boolean变量标识为是否已经取消,线程里每个循环地方加判断,变量变成了取消则停止循环:

private volatile boolean isCanceled = false;
new Thread(){
@Override
public void run() {
for (int i=0; i < 999 && !isCanceled; i++) {
System.out.println("哈哈,我还没死...");
}
}
}.start();
// kill thread
isCanceled = true;

点评: 太片面,线程里Thread.sleep(999999)取消不了的

3. 通过调用interrupt() :

Thread thread = new Thread(){
@Override
public void run() {
sleep(99999);
System.out.println("刚睡醒,我还没死!!!");
}
};
thread.start();
// kill you now
thread.interrupt();

点评:也是太片面,for循环取消不了

4. 以上方案意思是有那么一点了,只是零零碎碎,如何将两个方案结合是今天的第一个话题。

在Thread内提供了一个方法叫interrupted(), 其返回值即告知是否线程被interrupt()执行过,简单说:无需自己定义boolean变量,可以用它代替,如果线程能被interrupt()而停止正好,如果是内部循环操作可以用它作为循环停止的条件:

Thread thread = new Thread(){
@Override
public void run() {
for (int i=0; i < 999 && !Thread.interrupted(); i++) {
System.out.println("哈哈,我还没死...");
}
}
};

其实,还有一种情况是停止不了的,类似socket/http通信这种不能被interrputted的情况,当然也有巧妙的办法:重载Thread的interrput()方法:

// 重载interrupt 通过关闭socket起到关闭线程的作用
@Override
public void interrupt() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

今天的第二个话题是,使用单个线程的情况在项目中极少,很多情况使用线程池托管的,那么线程池里如何停止某个task呢?

JDK5提供了ExecuteService,并通过Executors提供了多个候选的线程池选择方案,ExecutorService提交task有两种方式:execute()和submit(), 我们这里对submit()比较感兴趣,因为其中submit()会返回Feature,不管submit的是 Runnable还是Callable都会有Feature返回:

public interface ExecutorService extends Executor {

/**
* Submits a value-returning task for execution and returns a
* Future representing the pending results of the task. The
* Future's {@code get} method will return the task's result upon
* successful completion.
*
* 
* If you would like to immediately block waiting
* for a task, you can use constructions of the form
* {@code result = exec.submit(aCallable).get();}
*
* 
Note: The {@link Executors} class includes a set of methods
* that can convert some other common closure-like objects,
* for example, {@link java.security.PrivilegedAction} to
* {@link Callable} form so they can be submitted.
*
* @param task the task to submit
* @param the type of the task's result
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
 Future submit(Callable task);
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's {@code get} method will
* return {@code null} upon successful completion.
*
* @param task the task to submit
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
Future> submit(Runnable task);
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's {@code get} method will
* return the given result upon successful completion.
*
* @param task the task to submit
* @param result the result to return
* @param the type of the result
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
 Future submit(Runnable task, T result);
}

Feature对象提供了一系列API,如:

cancel(boolean mayInterruptIfRunning) ;
isCanceled();
get();
get(long timeout, TimeUnit unit);
isDone()

看到第一个API,很是让人兴奋,难倒这真的可以一步到位?但很不好意思,依然不行,其实跟第一个话题的原理一摸一样,如果内部有阻塞线程的操作会因此而退出,如: wait(), join(), sleep() 等,但是遇到IO阻塞操作,比如进行socket通信,仅仅通过调用cancel(true)是不行的,不过可以重载interrupt() 关闭socket即可, 遇到大量循环也要通过Thread.interrupted()作为循环结束的条件:

class Task extends Thread{
private Socket socket;
public Task(){
// init socket
}
// 重载interrupt 通过关闭socket起到关闭线程的作用
@Override
public void interrupt() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void func () {
ExecutorService timer = Executors.newCachedThreadPool();
Future> future = timer.submit(new Task());
future.cancel(true);
}

好了,夜深了...回忆到此结束