Java终止线程实例和stop()方法源码阅读

 更新时间:2017年12月29日 15:19:24   作者:Rainmonth  
这篇文章主要介绍了Java终止线程实例和stop()方法源码阅读,具有一定借鉴价值,需要的朋友可以参考下

了解线程

概念

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

线程特点

拥有状态,表示线程的状态,同一时刻中,JVM中的某个线程只有一种状态;

·NEW

尚未启动的线程(程序运行开始至今一次未启动的线程)

·RUNNABLE

可运行的线程,正在JVM中运行,但它可能在等待其他资源,如CPU。

·BLOCKED

阻塞的线程,等待某个锁允许它继续运行

·WAITING

无限等待(再次运行依赖于让它进入该状态的线程执行某个特定操作)

·TIMED_WAITING

定时等待(再次运行依赖于让它进入该状态的线程在指定等待时间内某个特定操作)

·TERMINATED

已退出的线程

拥有优先级,决定线程的执行顺序;

1至10之间的整数,默认数值为5。数值越高,执行的几率越高,优先级并不能决定线程的执行顺序。

子线程的优先级默认同父线程的一样。

注意,当以下情况发生时,JVM将停止执行所有线程:

Runtime(运行时)的exit ()方法被调用并且该方法的调用被Security Manager所允许;

所有的“非守护线程”都已停止运行(无论时正常停止还是一场停止);

可以被标记为守护程序(Daemon)

守护线程的子线程仍是守护线程;

守护线程也就是“后台线程”,一般用来执行后台任务,而用户线程一般用户执行用户级任务。

终止线程的方法

1.使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){……}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。

FlagExitThread.java

package com.rainmonth;
/**
* Created by RandyZhang on 2017/3/23.
*/
public class FlagExitThread extends Thread {
	public volatile Boolean isExit = false;
	public FlagExitThread(String name) {
		super(name);
	}
	@Override
	  public void run() {
		while (!isExit) {
			System.out.println("I'm running");
		}
	}
}

DemoClient.java

package com.rainmonth;
/**
* Created by RandyZhang on 2017/3/23.
*/
public class DemoClient {
	public static void main(String[] args) {
		System.out.println("优雅的终止线程实例");
		exitByFlag();
		// exitByInterrupt();
	}
	private static void exitByFlag() {
		FlagExitThread flagExitThread = new FlagExitThread(FlagExitThread.class.getSimpleName());
		flagExitThread.start();
		try {
			Thread.sleep(1000);
			flagExitThread.isExit = true;
			flagExitThread.join();
			System.out.println("线程退出");
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	private static void exitByInterrupt() {
		FlagExitThread flagExitThread = new FlagExitThread(FlagExitThread.class.getSimpleName());
		System.out.println("flagExitThread running...");
		flagExitThread.start();
		try {
			Thread.sleep(1500);
			System.out.println("flagExitThread interrupted...");
			flagExitThread.interrupt();
			Thread.sleep(1500);
			System.out.println("stop application...");
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

输出结果:

打印了一大堆I'm running之后线程退出。

2.使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。

显示调用stop()方法。源码中关于stop() 的描述如下:

/*
* This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* <code>ThreadDeath</code> exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses of <code>stop</code> should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the <code>interrupt</code> method should be used to
* interrupt the wait.
*/

大意就是说,该方法的不安全性时固有的。调用stop()终止一个线程会释放它已经锁定的所有监视器(这将导致沿堆栈向上传播为检查的ThreadDeath异常被抛出),若此时之前受这些被释放的监视器保护的对象存在不一致性,并且这些对象对其他线程可见,这就会导致一些意想不到的后果。stop操作应该有哪些仅仅只需要修改某些代码就可以指示目标线程应该停止运行的代码来取代(方法一就是这种方式)。如果目标线程由于等待某一条件(如某个条件变量)等待很长时间,我们应该使用interrupt方法来中断该等待(方法三就是这种方式)。

3.使用interrupt方法中断线程。

interrupt字面上是终止的意思,但不要试图通过调用interrupt来终止线程,因为有时即使你调用了该方法,线程仍然会继续执行,可以注释掉上面的exitByFlag(),开启exitByInterrupt() 方法,发现及时调用了interrupt()方法,仍在一直输出I'm running…(不同系统及CPU结果可能有所不同),可见采用interrupt方式也是不安全的。

总结

根据以上的分析,最值得推荐的方式是第一种,我们可以用共享变量(shared variable)的方式来设置标志,并发出信号,通知线程必须终止。当然对这个共享变量的操作我们必须保证是同步的。

以上就是本文关于Java终止线程实例和stop()方法源码阅读的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

相关文章

  • Mac M1安装JDK的实战避坑指南

    Mac M1安装JDK的实战避坑指南

    这篇文章主要给大家介绍了关于Mac M1安装JDK避坑的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-02-02
  • Spring框架实现滑动验证码功能的代码示例

    Spring框架实现滑动验证码功能的代码示例

    之前项目需要在验证码模块,增加滑动验证码,用来给手机端使用的,大概看了下,主要方法就是将图片切割,然后记住偏移量,进行滑动,所以本文给大家介绍了Spring框架实现滑动验证码功能的方法示例,需要的朋友可以参考下
    2024-07-07
  • logback的UNDEFINED_PROPERTY属性源码执行流程解读

    logback的UNDEFINED_PROPERTY属性源码执行流程解读

    这篇文章主要为大家介绍了logback的UNDEFINED_PROPERTY属性源码执行流程解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 使用Java代码实现Redis和数据库数据同步

    使用Java代码实现Redis和数据库数据同步

    这篇文章主要介绍了使用Java代码实现Redis和数据库数据同步问题,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-06-06
  • Spring之SseEmitter实现让你的进度条实时更新

    Spring之SseEmitter实现让你的进度条实时更新

    Spring SseEmitter是一种实现服务器端推送事件(SSE)的机制,支持单向通信,适用于实时数据传输需求,通过代码示例和应用场景分析,展示了如何在服务端和客户端使用SseEmitter进行实时数据推送
    2025-02-02
  • 在Java中实现可见性(visibility)的主要方法详解

    在Java中实现可见性(visibility)的主要方法详解

    这篇文章主要介绍了在Java中实现可见性(visibility)的主要方法详解,在Java中,使用关键字volatile和使用锁(如synchronized关键字或 java.util.concurrent包中的锁)来确保对共享变量的修改在多线程环境中能够正确地被其他线程所观察到,需要的朋友可以参考下
    2023-08-08
  • 详解Java @Documented注解的作用

    详解Java @Documented注解的作用

    @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,本文将通过示例详细说说@Documented注解的作用,需要的可以参考一下
    2022-09-09
  • java若依框架集成redis缓存详解

    java若依框架集成redis缓存详解

    今天小编就为大家分享一篇关于java若依框架集成redis缓存的实现,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • springboot 用监听器统计在线人数案例分析

    springboot 用监听器统计在线人数案例分析

    这篇文章主要介绍了springboot 用监听器统计在线人数案例分析,质是统计session 的数量,思路很简单,具体实例代码大家参考下本文
    2018-02-02
  • 在Java8与Java7中HashMap源码实现的对比

    在Java8与Java7中HashMap源码实现的对比

    这篇文章主要介绍了在Java8与Java7中HashMap源码实现的对比,内容包括HashMap 的原理简单介绍、结合源码在Java7中是如何解决hash冲突的以及优缺点,结合源码以及在Java8中如何解决hash冲突,balance tree相关源码介绍,需要的朋友可以参考借鉴。
    2017-01-01

最新评论