如何构造线程

在运行线程之前需要先构造线程对象,线程对象的构造需要指定线程所需要的属性,比如:所属线程组、线程优先级、是否为Daemon线程等信息。下面我们看一下,java.lang.Thread中对线程初始化的方法:

  1. private void init(ThreadGroup g, Runnable target, String name,
  2. long stackSize, AccessControlContext acc,
  3. boolean inheritThreadLocals) {
  4. if (name == null) {
  5. throw new NullPointerException("name cannot be null");
  6. }
  7. //线程名称
  8. this.name = name;
  9. //当前线程就是该线程的父线程
  10. Thread parent = currentThread();
  11. SecurityManager security = System.getSecurityManager();
  12. if (g == null) {
  13. /* Determine if it's an applet or not */
  14. /* If there is a security manager, ask the security manager
  15. what to do. */
  16. if (security != null) {
  17. g = security.getThreadGroup();
  18. }
  19. /* If the security doesn't have a strong opinion of the matter
  20. use the parent thread group. */
  21. if (g == null) {
  22. g = parent.getThreadGroup();
  23. }
  24. }
  25. /* checkAccess regardless of whether or not threadgroup is
  26. explicitly passed in. */
  27. g.checkAccess();
  28. /*
  29. * 是否有访问权限
  30. */
  31. if (security != null) {
  32. if (isCCLOverridden(getClass())) {
  33. security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
  34. }
  35. }
  36. g.addUnstarted();
  37. //线程组
  38. this.group = g;
  39. //使用父线程的daemon、priority属性
  40. this.daemon = parent.isDaemon();
  41. this.priority = parent.getPriority();
  42. if (security == null || isCCLOverridden(parent.getClass()))
  43. this.contextClassLoader = parent.getContextClassLoader();
  44. else
  45. this.contextClassLoader = parent.contextClassLoader;
  46. this.inheritedAccessControlContext =
  47. acc != null ? acc : AccessController.getContext();
  48. this.target = target;
  49. setPriority(priority);
  50. if (inheritThreadLocals && parent.inheritableThreadLocals != null)
  51. this.inheritableThreadLocals =
  52. ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
  53. /* Stash the specified stack size in case the VM cares */
  54. this.stackSize = stackSize;
  55. /* 分配一个线程ID */
  56. tid = nextThreadID();
  57. }

一个 新 构造 的 线程 对象 是 由其 parent 线程 来 进行 空间 分配 的, 而 child 线程 继承 了 parent 是否 为 Daemon、 优先级 和 加载 资源 的 contextClassLoader 以及 可继承 的 ThreadLocal, 同时 还会 分配 一个 唯一 的 ID 来 标识 这个 child 线程。 至此, 一个 能够 运行 的 线程 对象 就 初始化 好了, 在 堆 内存 中 等待 着 运行。

我们构造一个Thread thread=new Thread(),打上断点,可以看到thread对象的属性如下:

如何使用线程

实现多线程编程的方式主要有两种:一种是继承Thread类,一种是实现Runnable接口,使用继承Thread类最大的局限性是不支持多继承,由于java单继承的特性,为了突破单继承的限制,于是就有了另一个实现方式,就是实现Runnable接口。使用这两种方式创建的线程工作性质是一样的,没有本质的区别。

继承Thread类

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. System.out.println("我是自定义线程MyThread");
  6. }
  7. }

实现Runnable接口

  1. public class MyRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("我是Runnable");
  5. }
  6. }

如何启动线程

线程对象初始化完成后,调用线程的start()方法就可以启动线程了,start()方法是告诉Java虚拟机,如果线程规划期空闲,应该立即启动调用了start()方法的线程。

同一个线程不能多次 调用 start() 方法, 否则会出现异常 Exception in thread” main” java. lang. IllegalThreadStateException。

线程的start()方法,会新启动一个线程,而线程run()方法则是同步等待当前线程调用。

如何停止线程

如何判断线程是否停止

在介绍如何停止线程的知识点前, 先看一下如何判断线程是否停止的状态。 Thread.java类中提供了两个很重要的方法:

1) this.interrupted(): 判断当前线程是否已经中断

2) this.isInterrupted(): 判断线程是否已经中断

那么这两种方法的区别是什么呢? 先来看看 this.interrupted()方法: 判断当前线程是否已经中断,当前线程是指运行 this. interrupted()方法 的 线程。

  1. public static void main(String[] args) {
  2. Thread.currentThread().interrupt();
  3. String threadName = Thread.currentThread().getName();
  4. System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted());
  5. System.out.println(threadName + " 当前线程是否已停止:=" + Thread.interrupted());
  6. }
  7. main 当前线程是否已停止:=true
  8. main 当前线程是否已停止:=false

从执行结果可知 interrupt()方法确实停止了线程,但是第二个判断结果为什么是false呢,通过查看官方文档当解释得知。interrupted() 具有清除状态的功能,所以第二个判断结果为false

下面我们接着查看 isInterrupted()方法:

  1. public static void main(String[] args) {
  2. Thread.currentThread().interrupt();
  3. String threadName = Thread.currentThread().getName();
  4. System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted());
  5. System.out.println(threadName + " 当前线程是否已停止:=" + Thread.currentThread().isInterrupted());
  6. }
  7. main 当前线程是否已停止:=true
  8. main 当前线程是否已停止:=true

输出的结果都为true,isInterrupted()并未清除状态标志,最后我们得出如下结论:

1) this.interrupted(): 判断线程终止的状态, 执行后具有将状态标志置为false的功能

2) this.isInterrupted():判断线程终止的状态,不具有清除状态标志的功能

try..catch与this.interrupt方法终止线程

  1. public class MyThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. for (int i = 0; i < 5000; i++) {
  6. if (interrupted()) {
  7. System.out.println(Thread.currentThread().getName() + " 我被停止了,退出循环");
  8. break;
  9. }
  10. System.out.println(" i=" + (i + 1));
  11. }
  12. }
  13. }
  14. public static void main(String[] args) {
  15. MyThread thread = new MyThread();
  16. thread.setName("Thread-interrupt-0");
  17. thread.start();
  18. try {
  19. Thread.sleep(1);
  20. thread.interrupt();
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. System.out.println(" 结束!");
  25. }
  26. 输出结果:
  27. .....
  28. i=32
  29. i=33
  30. i=34
  31. i=35
  32. i=36
  33. i=37
  34. i=38
  35. i=39
  36. i=40
  37. i=41
  38. 结束!
  39. Thread-interrupt-0 我被停止了,退出循环

过期的 suspend()、 resume() 和 stop()方法终止线程

suspend()在调用后线程不会释放已经占有的资源,二是占有着资源进入睡眠状态,这样容易引发死锁问题。同样的stop()方法在终止一个线程时不会保证线程的资源正常释放,通常线程没有机会去释放资源,因此会导致程序工作状态的不确定性。

正是因为 suspend()、 resume() 和 stop() 方法 带来的副作用, 这些方法才被标志位不建议使用的过期方法, 而暂停和恢复可以使用 等待/ 通知机制 来替代。

Java线程的启动和停止(一)的更多相关文章

  1. Java线程的启动与中止

    一.线程与进程的关系 关于进程与线程,百度百科上是这样描述的: 进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 在当 ...

  2. 面试官:Java 线程如何启动的?

    摘要:Java 的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢? 本文分享自华为云社区<Threa ...

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

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

  4. java -jar shell 启动、停止

    启用 vi start.sh #!/bin/sh # ################################################################## # Powe ...

  5. java线层的启动与停止

    class Do8 { public static void main(String[] args) { Resource r =new Resource(); Input in =new Input ...

  6. JAVA线程初体验

    线程的创建 线程的启动和停止 /** * 演员类 继承Thread类 * @author Administrator * */ public class Actor extends Thread { ...

  7. Java线程池的那些事

    熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但 ...

  8. 基于 JVMTI 实现 Java 线程的监控(转)

    随着多核 CPU 的日益普及,越来越多的 Java 应用程序使用多线程并行计算来充分发挥整个系统的性能.多线程的使用也给应用程序开发人员带来了巨大的挑战,不正确地使用多线程可能造成线程死锁或资源竞争, ...

  9. 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考

    2018年12月12日18:44:53 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考 案件现场 不久前,在开发改造公司一个端到端监控日志系统的时候,出现了一 ...

随机推荐

  1. Elastic Search快速上手(3):搜索

    前言 存储好数据之后,便可通过RESTful API进行搜索. 详细文档可参考: --简单搜索https://www.elastic.co/guide/cn/elasticsearch/guide/c ...

  2. MyEclipse10.0 采用插件方式安装 SVN

    一.到官方上下载svn1.8.3,下载后的文件名叫site-1.8.3.zip 地址:http://subclipse.tigris.org/servlets/ProjectDocumentList? ...

  3. VBA学习资料分享-3

    VBA创建/发送OUTLOOK邮件时怎么加上默认签名呢?用过OUTLOOK写邮件的人都知道,如果你设置了默认签名,那么在创建空白邮件的时候就会自动加上你设置的签名.根据这一特性,我们可以在用VBA创建 ...

  4. Graphics与Canvas

    Graphics: 1. java.awt.Graphics;2.android.graphics Canvas:1.java.awt.Canvas;2.android.graphics.Canvas ...

  5. Linux下安装opencv(踩坑记录帖)

    1.首先安装依赖项:sudo apt install build-essential sudo apt install build-essentialsudo apt install cmake gi ...

  6. 牛客练习赛51 C 勾股定理 (数学,结论)

    链接:https://ac.nowcoder.com/acm/contest/1083/C来源:牛客网 题目描述 给出直角三角形其中一条边的长度n,你的任务是构造剩下的两条边,使这三条边能构成一个直角 ...

  7. java线程基础巩固---如何捕获线程运行期间的异常

    对于友盟统计我想搞程序的应该无人不晓,其中对于里面用得最多的功能就是对线上的崩溃进行修复,而这些异常都是运行期的,如: 其实也就是可以对线程中出现了这种运行期异常是提供有一种捕获机制对其进行统一处理, ...

  8. pip报错以及指向错误

    在终端中输入无论是pip3 -V或是pip -V都指向python3 如下图所示: 然后在卸载或更新pip 时都出现了报错: 就是卸载也卸不了更新也更不了 解决报错: Traceback (most ...

  9. js文件中使用el表达式问题

    作者:Sang 单独js文件不能用el表达式. 首先,JSP是由服务端执行的,EL表达式自然也由服务端解析执行,因此如果EL所在的脚本在JSP页面内,它是可以获取到值的,这个值在服务器端返回到浏览器端 ...

  10. Linux防CC攻击脚本

    多数CC攻击在web服务器日志中都有相同攻击的特征,我们可以根据这些特征过滤出攻击的ip,利用iptables来阻止 #!/bin/bash #by LinuxEye #BLOG: http://bl ...