如何让一个线程“优雅”地退出

如何让一个线程“优雅”地退出

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

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

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

代码语言:javascript复制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

代码语言:javascript复制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了。

代码语言:javascript复制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中,如何优雅的关闭线程 代码语言:javascript复制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();

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

参考线程中断方法interrupt、isInterrupted、interrupted方法_CBeann的博客-CSDN博客

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

你可能也喜欢

魔兽8.1踏风武僧入门PVP心得分享 机动强伤害高
365体育网址备用

魔兽8.1踏风武僧入门PVP心得分享 机动强伤害高

📅 02-02 👀 7544
雄玖二手电脑显示器专营店
365体育网址备用

雄玖二手电脑显示器专营店

📅 01-03 👀 8810
如何使用 表格的组合功能
365bet繁体中文

如何使用 表格的组合功能

📅 01-22 👀 7719
《塞尔达传说:旷野之息》哪里有大量矿石
365bet皇冠体

《塞尔达传说:旷野之息》哪里有大量矿石

📅 01-06 👀 5270
《神武4》平民玩家囤一只可爱珍兽要多久?
365体育网址备用

《神武4》平民玩家囤一只可爱珍兽要多久?

📅 11-07 👀 4325
男生为什么会肾虚
365体育网址备用

男生为什么会肾虚

📅 07-06 👀 2414
梦幻手游坐骑价格一览购买成本分析与建议,梦幻西游手游坐骑多少钱
MySQL 关联两张表 常用的几种方法
365体育网址备用

MySQL 关联两张表 常用的几种方法

📅 07-10 👀 4326
大薸种子怎么挑选?育苗方法有哪些?
365体育网址备用

大薸种子怎么挑选?育苗方法有哪些?

📅 08-31 👀 1803