这篇文章我们来讨论一下终止线程运行的方法;
中断线程的方法:
public static void stopThread() throws InterruptedException{
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()){
System.out.print("run,");
}
}
});
t.start();
//1毫秒后发送中断命令
TimeUnit.MILLISECONDS.sleep(1);
t.interrupt();
System.out.println("\r\n中断完毕,主线程运行完毕!");
}
输出**********************************************************************
run,run,run,run,run,run,run,run,run,run,run,
中断完毕,主线程运行完毕!
***************************************************************************
而在主线程中,我们等待1毫秒后对 t 这个线程发送中断命令,在输出结果中可以看到,t线程已成功停止运行;
停止线程池中全部线程的方法:
class StopThread implements Runnable{
@Override
public void run() {
try {
System.out.println("run...");
TimeUnit.MILLISECONDS.sleep(2000);
System.out.println("run...over...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//终止线程池内全部线程
public static void stopAllThread() throws InterruptedException{
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.execute(new StopThread());
}
//这将立即中断该线程池内所有运行或者阻塞的线程
exec.shutdownNow();
System.out.println("stopBlocking()...over...");
}
输出********************************************************************************
run...
run...
stopBlocking()...over...
run...
run...
run...
***********************************************************************************
可以看到,所有线程都只打印出了run...而没有打印run...over... 这代表它们已经被成功停止了!
需要注意的是:如果我们调用exec.shutdown(),这会让已经处于运行中的任务继续运行下去而不会被成功停止...
停止线程池中单个线程的方法:
//终止单个线程
public static void stopSingleThread(){
ExecutorService exec = Executors.newCachedThreadPool();
List fs = new ArrayList();
for (int i = 0; i < 5; i++) {
Future f = exec.submit(new StopThread());
fs.add(f);
}
//立即停止第一个线程!如果参数为false,则等待任务执行完毕;
fs.get(0).cancel(true);
}
输出*****************************************************************************
run...
run...
run...
run...
run...
run...over...
run...over...
run...over...
run...over...
**********************************************************************************
这个输出结果是没问题的,因为有一个线程已经被停止了,所以只有四行run...over...打印;
我们通过改为调用exec的submit方法而不是execute方法 从而拿到一个Future对象,每个Future对应于一个运行着的线程,当我们调用Future的cancel(true)方法时,对应的线程将终止运行;论证:IO阻塞和等待synchronized锁造成的阻塞中的线程无法被中断!
Object tempObj = new Object();
private static void holdLock(){
//开启一个线程持有tempObj的锁
new Thread(new Runnable() {
public void run() {
synchronized (tempObj) {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {}
}
}
}).start();
}
//证明IO阻塞和等待锁阻塞中的线程无法被中断!
public static void stopByIoAndLockThread() throws IOException{
holdLock();
final InputStream in = System.in;
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Runnable() {
public void run() {
System.out.println("io Blocking...");
try {
//等待IO读写
in.read();
System.out.println("io Blocking...over...");
} catch (IOException e) {
e.printStackTrace();
}
}
});
exec.execute(new Runnable() {
public void run() {
System.out.println("Lock Blocking...");
//等待对象锁,已在holdLock()中被持有
synchronized (tempObj) {
System.out.println("Lock Blocking...over...");
}
}
});
//中断这两个线程,我们可以看输出,这代码压根没效果
exec.shutdownNow();
}
你可以复制上面的代码去运行一下,事实证明处理这两种阻塞中的线程时无法停止的;
由此引入了一个问题,如果某个线程获取了对象锁,但它运行之中出现了问题导致锁一直不被释放,我们又希望能终止该线程的运行好让其它线程能拿到锁从而做些操作,此时该怎么办呢?答案是不采用synchronized进行同步操作,而采用ReentrantLock;
代码如下:
//synchronized造成的阻塞让线程无法停止,但java的Lock对象造成的阻塞是可以让线程停止的!
public static void allowStopByLock(){
System.out.println("allowStopByLock()...");
final ReentrantLock lock = new ReentrantLock();
lock.lock();//永久的持有锁
Thread thread = new Thread(new Runnable() {
public void run() {
try {
System.out.println("准备获取lock锁...");
//如果当前线程未中断,则获取锁
lock.lockInterruptibly();
System.out.println("已获取到锁,执行完毕!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
//interrupt方法调用完后可以看到线程已经停止了
thread.interrupt();
System.out.println("allowStopByLock()...over...");
}
Ok,关于停止线程运行的相关方法就讲到这里;后面我们开始来讲点真正有用的东西!