stop强制退出(十分不推荐)

        记住,线程的终止,并不是简单的调用 stop 命令去。虽然 api 仍然可以调用,但是和其他的线程控制方法如 suspend、resume 一样都是过期了的不建议使用,就拿stop 来说,stop 方法在结束一个线程时并不会保证线程的资源正常释放,因此会导致程序可能出现一些不确定的状态。(参考​​如何优雅的"中断"一个线程? - 简书​​)

class MyThreadForStop extends Thread {
@Override
public void run() {

while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
}

System.out.println(LocalDateTime.now().toString());
}

}
}
public static void main(String[] args) {


MyThreadForStop m1 = new MyThreadForStop();
m1.start();
//睡5秒
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
//关闭当前线程
m1.stop();


}

使用标记字段

如下面的demo,所示,定义一个成员变量,通过这个成员变量去控制,每次循环都判断这个变量的状态,从而确定是否要退出。但是这个时候是有一个问题的,比如我在循环中执行一个阻塞的方法,比如阻塞的队列的取操作,如果队列里没有数据,该线程在阻塞状态,我们想停止,但是此时使用标记字段就无能为力了。

class MyThreadForSign extends Thread {

//volatile标记
private volatile boolean stop = false;


public void stopThread() {
stop = true;
}

@Override
public void run() {

while (!stop) {
System.out.println(LocalDateTime.now().toString());
}

}
}

MyThreadForSign m1 = new MyThreadForSign();
m1.start();
//睡5秒
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
//关闭当前线程,修改标记位
m1.stopThread();

interrupt 方法

线程Thread.currentThread().isInterrupted() 默认为false,当你调用interrupt方法后,仅仅是给线程打一个标记,Thread.currentThread().isInterrupted()就会返回true

class MyThreadForInterrupt extends Thread {

@Override
public void run() {

while (!Thread.currentThread().isInterrupted()) {
System.out.println(LocalDateTime.now().toString());
}

}
}

MyThreadForInterrupt m1 = new MyThreadForInterrupt();
m1.start();
//睡5秒
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
//标记中断
m1.interrupt();

当线程在sleep中,如何优雅的关闭线程

main方法和上面的一样,不贴了,当线程在sleep中,在main方法执行interrupt方法时,会出现异常,此时查看当前线程的中断状态为false(虽然我们调用了interrupt方法,理论上为true,但是sleep的线程不会标记成功),我们只需要捕捉到然后在重新标记,然后就ok了。

class MyThreadForInterrupt extends Thread {


@Override
public void run() {

while (!Thread.currentThread().isInterrupted()) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
//当前线程的中断状态
System.out.println("Thread.currentThread().isInterrupted():"+Thread.currentThread().isInterrupted());
//重新设置中断
this.interrupt();
} finally {
}

System.out.println(LocalDateTime.now().toString());
}

}
}

当线程在wait中,如何优雅的关闭线程 

class MyThreadForInterrupt extends Thread {

Lock lock;
Condition condition;

public MyThreadForInterrupt(Lock lock) {
this.lock = lock;
this.condition = lock.newCondition();
}


@Override
public void run() {


while (!Thread.currentThread().isInterrupted()){
System.out.println(LocalDateTime.now().toString());
lock.lock();
try {
//线程在阻塞状态
condition.await();
} catch (Exception e) {
e.printStackTrace();
//当前线程的中断状态
System.out.println("Thread.currentThread().isInterrupted():" + Thread.currentThread().isInterrupted());
this.interrupt();

} finally {
lock.unlock();
}
}


}
}


public static void main(String[] args) {

Lock lock = new ReentrantLock();


MyThreadForInterrupt m1 = new MyThreadForInterrupt(lock);
m1.start();
//睡5秒
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
//标记中断
m1.interrupt();


}

总结

其实都是抛异常,然后捕捉到异常,重新打标记,然后下次循环就能发现标记发生修改,然后就退出了。

参考


​如何优雅的"中断"一个线程? - 简书​