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

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

最简单的代码:

 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;
} }

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

Java 如何正确停止一个线程的更多相关文章

  1. java如何正确停止一个线程

    Thread类中有start(), stop()方法,不过stop方法已经被废弃掉. 平时其实也有用过,共享一个变量,相当于标志,不断检查标志,判断是否退出线程 如果有阻塞,需要使用Thread的in ...

  2. Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程

    下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...

  3. Java并发(基础知识)—— 创建、运行以及停止一个线程

    在计算机世界,当人们谈到并发时,它的意思是一系列的任务在计算机中同时执行.如果计算机有多个处理器或者多核处理器,那么这个同时性是真实发生的:如果计算机只有一个核心处理器那么就只是表面现象. 现代所有的 ...

  4. Java再学习——停止一个正在运行的线程

    关于这个问题,先了解一下Thread类方法中被废弃的那些方法.suspend(), resume(),stop()/stop(Throwable obj),destroy() 首先,stop(Thro ...

  5. java停止一个线程

    Thread类中有start(), stop()方法,不过stop方法已经被废弃掉. 平时其实也有用过,共享一个变量,相当于标志,不断检查标志,判断是否退出线程 如果有阻塞,需要使用Thread的in ...

  6. 别指望一文读懂Java并发之从一个线程开始

    Understanding concurrent programming is on the same order of difficulty as understanding object-orie ...

  7. java holdsLock()方法检测一个线程是否拥有锁

    http://blog.csdn.net/w410589502/article/details/54949506 java.lang.Thread中有一个方法叫holdsLock(),它返回true如 ...

  8. JAVA多线程之当一个线程在执行死循环时会影响另外一个线程吗?

    一,问题描述 假设有两个线程在并发运行,一个线程执行的代码中含有一个死循环如:while(true)....当该线程在执行while(true)中代码时,另一个线程会有机会执行吗? 二,示例代码(代码 ...

  9. Java自学-多线程 启动一个线程

    Java 创建一个线程的三种方式 多线程即在同一时间,可以做多件事情. 创建多线程有3种方式,分别是继承线程类,实现Runnable接口,匿名类 步骤 1 : 线程概念 首先要理解进程(Process ...

随机推荐

  1. 简单Maven Dos命令语句

    简单Maven Dos命令语句: 打包:mvn package 编译:mvn compile 编译测试程序:mvn test-compile 清空:mvn clean 运行测试:mvn test 生成 ...

  2. BigData--hadoop集群搭建之zookeer安装

    Zookeeper安装 cd /opt/ tar -zxvf zookeeper-3.4.10.tar.gzmv zookeeper-3.4.10  /opt/zookeeper修改配置文件cd /o ...

  3. webug学习(1)

    webug的题目,比较简单,拿来巩固一哈. 1. 一看就知道是注入漏洞了,啥也不说sqlmap直接开炮. 先-u 之后-u 网址 --current-db 获取当前网址的数据库 所以当前数据库就是 p ...

  4. JavaScript实现判断图片是否加载完成的3种方法整理

    JavaScript实现判断图片是否加载完成的3种方法整理 有时候我们在前端开发工作中为了获取图片的信息,需要在图片加载完成后才可以正确的获取到图片的大小尺寸,并且执行相应的回调函数使图片产生某种显示 ...

  5. 嵌入式linux系统移植(一)

    内容:   交叉编译环境   bootloader功能子系统   内核核心子系统   文件系统子系统要点:  搭建交叉编译环境  bootloader的选择和移植  kernel的配置.编译.移植和调 ...

  6. linux文件操作篇 (二) 打开和关闭文件

    2.1 打开文件和关闭文件 #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>  头文件 i ...

  7. Infinite Maze CodeForces - 196B

    We've got a rectangular n × m-cell maze. Each cell is either passable, or is a wall (impassable). A ...

  8. crest value &minimum

    public class paixu { public static void main(String[] args) { double temp; double num[]={5.1, 7.12, ...

  9. Jupyter Notebook里面使用Matplotlib画图 图表中文乱码问题

    可查看以下链接: https://blog.csdn.net/ccblogger/article/details/79613335

  10. Kubernetes-深入分析集群安全机制

    Kubernetes过一系列机制来实现集群的安全机制,包括API Server的认证授权.准入控制机制及保护敏感信息的Secret机制等.集群的安全性必须考虑以下的几个目标: 保证容器与其所在宿主机的 ...