安全的终止线程
线程正常执行结束,就会终止
除了正常结束外,还有什么方法终止?
设置线程终止标志
public class FlagThread extends Thread {
/**
* 退出标识
*/
public volatile boolean exit = false;
@Override
public void run() {
while (!exit);
System.out.println("ThreadFlag线程退出");
}
public static void main(String[] args) throws Exception
{
FlagThread threadFlag = new FlagThread();
threadFlag.start();
// 主线程延迟3秒
sleep(3000);
// todo 终止线程thread
threadFlag.exit = true;
// main线程放弃cpu使用权
// 让threadFlag线程继续执行,直到threadFlag运行完
threadFlag.join();
System.out.println("线程退出!");
}
}
上面代码定义了退出标志exit,为true的时候,会退出,默认为false,在定义exit时,用volatile 修饰,这个关键字的目的是保证exit内存可见性,就是exit被修改的时候立刻对其他线程可见。
中断的方式终止线程
当线程阻塞时,使线程处于不可运行状态时,即使主线程中该线程的退出标志设置为true,但是该线程此时根本无法检测循环标志,当然就无法立即中断。
public class InterruptThread extends Thread {
/**
* 退出标识
*/
volatile boolean exit = false;
@Override
public void run() {
while (!exit) {
System.out.println(getName() + " is running");
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
System.out.println("week up from block...");
exit = true; // 在异常处理代码中修改共享变量的状态
}
}
System.out.println(getName() + " is exiting...");
}
public static void main(String[] args) throws InterruptedException {
InterruptThread interruptThread = new InterruptThread();
System.out.println("Starting thread...");
interruptThread.start();
Thread.sleep(3000);
System.out.println("Interrupt thread...: " + interruptThread.getName());
// 设置退出标识为true
interruptThread.exit = true;
// todo 阻塞时退出阻塞状态
// interruptThread.interrupt();
// 主线程休眠3秒以便观察线程interruptThread的中断情况
Thread.sleep(3000);
System.out.println("Stopping application...");
}
}
由图片可见代码执行到41行了,但是没有执行完。
因为主线程Thread.sleep(3000)时interruptThread执行了,代码中通过 Thread.currentThread().join();让出了cpu使用权,这时主线程继续,就算设置interruptThread,exit为true,但是interruptThread还卡在那个地方,无法检测到,所以没有向下走,主线程就继续往下走了。这时如果把38行注释打开,run方法的方法体会报错被catch,不再阻塞,这时会输出week up from block并且修改状态,被检测到,然后退出。
废弃的终止线程的方式,工作中不要用,但是可以了解一下
Thread.stop()----类似电脑直接拔掉电源,强行终止线程,后果不可预料。它会强行释放子线程持有的锁,导致被保护的资源出现线程安全问题。,会抛出一个ThreadDeath,这个继承了Error,会抛error。
Thread.suspend/Thread.resume----使线程暂停,不会释放锁的资源/resume使线程回复,suspend和resume必须成对出现,否则不起效果。但是很难控制这个先后顺序,容易造成死锁。
Runtime.runFinalizersOnExit---这个方法本身不是线程安全的