首页 技术 正文
技术 2022年11月21日
0 收藏 364 点赞 4,326 浏览 3734 个字

自己在做实验性小项目的时候,发现自己遇到一个问题:如何控制线程的”死亡”?

首先,如何开启一个线程呢?

最简单的代码:

 public class Main {     public static void main(String[] args) {         Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread() + ",当前时间戳:" + System.currentTimeMillis());
}
}); thread.start(); try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}
}

很简单,调用.start()方法,这个线程就会启动.

那么怎样主动去停止一个线程呢?要解答这个问题,首先要考虑:为什么要结束一个线程.

理由如下:

  • 线程是JVM宝贵的资源,有的线程会长时间占用资源.
  • 一些业务逻辑下会出现一个线程从逻辑上完全没有意义(比如一个定时器,调用了结束的方法),确实需要去停止.

结束一个线程有一个最基本的方法:Thread.stop()方法:

 @Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
} // The VM can handle all thread states
stop0(new ThreadDeath());
}

但是这个方法已经是:@Deprecated的了,也就是被建议不要使用的方法.

为什么不建议使用这个方法的官方说明: http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html

实际上,我结合自己经验提出以下几点:

  • 线程会直接停掉,按照代码逻辑要释放的资源,要调用的接口可能不会被运行(finally块的代码还是会执行)
  • 会破坏锁,导致线程不安全(停掉一个线程就会释放它持有的锁,但不能保证逻辑上)

这两点都是非常严重的问题了.即使再小心,去调用stop()也会导致各种各样的问题.

如果不能”硬”实现结束线程,那么就可以考虑下”软”实现.

首先,导致一个线程长时间运行的原因无非有这么几个:

  • 代码逻辑混乱\业务复杂,写了一个很长的run()方法
  • 长时间睡眠
  • 循环

对于这第一种嘛,只能从代码结构上优化了.

而这第二种,就要使用Thread.interrupt()方法了.这个方法唤醒睡眠中的线程:

 public class Main {     public static void main(String[] args) {         Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.DAYS.sleep(1L);
System.out.println("睡眠结束");
} catch (Exception e) {
System.out.println("异常:" + e);
} finally {
System.out.println("finally块被执行");
}
}
}); thread.start(); if (!thread.isInterrupted()) {
thread.interrupt();
}
System.out.println("主线程结束");
}
}

在bio的服务端里面,会阻塞当前线程.监听的端口有消息,才会继续执行,而如果没有人连接,就需要通过这种方式来打断正在监听的线程.

对于这第三种,需要通过轮询标志位来控制退出.自己写的定时器代码:

 public class TimerImpl implements Timer {     private static final Logger logger = LoggerFactory.getLogger(TimerImpl.class);     // 定时器线程
private TimerThread timerThread = null; private volatile Boolean running = false; private Handler taskHandler; private Long time; private TimeUnit unit; @Override
public void start() throws Exception { // 给参数生成本地固定拷贝,以确保在运行过程中,不会给参数的改变干扰
Handler curTask = taskHandler.getClass().newInstance();
Long curTime = new Long(time);
TimeUnit curUnit = unit.getClass().newInstance(); // 检查
if (ParameterUtil.checkNull(curTask, curTime, curUnit)) {
throw new Exception("定时器参数配置错误");
} if (!running) {
synchronized (running) {
if (!running) {
timerThread = new TimerThread(); timerThread.setTaskHandler(curTask);
timerThread.setTime(curTime);
timerThread.setUnit(curUnit); timerThread.start();
running = true;
}
}
}
} @Override
public void stop() throws Exception { if (!running) {
throw new Exception("定时器尚未开始");
} synchronized (running) {
if (running) {
// 标志位
timerThread.cancel();
// 打断睡眠
if (!timerThread.isInterrupted()) {
timerThread.interrupt();
}
running = false;
}
}
} private class TimerThread extends Thread { private volatile boolean stop = false; private Handler taskHandler; private Long time; private TimeUnit unit; @Override
public void run() { // circle
while (!stop) { // sleep
try {
unit.sleep(time);
} catch (InterruptedException e) {
logger.info("定时线程被打断,退出定时任务");
stop = true;
return;
} // do
try {
taskHandler.execute();
} catch (Exception e) {
logger.error("handler执行异常:{}", this.getClass(), e);
}
}
} public void cancel() {
stop = true;
} public Handler getTaskHandler() {
return taskHandler;
} public void setTaskHandler(Handler taskHandler) {
this.taskHandler = taskHandler;
} public Long getTime() {
return time;
} public void setTime(Long time) {
this.time = time;
} public TimeUnit getUnit() {
return unit;
} public void setUnit(TimeUnit unit) {
this.unit = unit;
}
} @Override
public void setTimer(Long time, TimeUnit unit) {
this.time = time;
this.unit = unit;
} @Override
public void setHandler(Handler handler) {
this.taskHandler = handler;
} }

想要停止一个线程的方法是有的,但是会麻烦一些.

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,077
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,552
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,401
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,176
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,813
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,896