1、  线程生命周期概述

线程的生命周期如下图:

2、  新建与就绪

当程序使用new关键字创建一个线程之后,线程就处于新建状态了。此时线程只是被分配了内存资源,初始化了成员变量。

当线程对象被调用了start()方法之后,该线程就处于就绪状态了。表示这个线程可以运行但还没有运行,至于线程何时开始运行,取决于jvm的线程调度器。

有一点值得注意,启动线程应该使用start()方法,而不是run()方法。如果使用run()方法,程序会把run()方法当成一个普通方法立刻执行,而不会启动新线程。

此外,也不可以对已就绪的线程再次调用start()方法,会引发异常。

3、  阻塞与运行

当就绪的线程获得CPU资源开始执行方法体,该线程就变成运行状态。当线程在运行的过程中被中断,则线程变为阻塞状态。被阻塞的线程在合适的时候会重新进入就绪状态,然后再次获取CPU资源,进入运行状态。

以下情况将使线程进入阻塞状态:

  • 线程调用sleep方法,主动放弃所占CPU资源。
  • 线程掉用了一个阻塞式IO方法,在方法返回前,线程被阻塞。
  • 线程试图获取一个同步锁,但是该锁被其他线程占有。
  • 线程在等待通知(线程同步notify)
  • 线程调用suspend方法挂起。该方法容易死锁,少用。

以下情况将解除阻塞状态,使线程重新进入就绪状态:

  • sleep方法计时结束
  • 阻塞式IO方法已经返回
  • 获取了同步锁
  • 等到了其他线程发出的通知
  • 调用resume方法解除了挂起状态

此外,调用yield方法可以使运行状态的线程直接转入就绪状态。

4、  线程死亡

以下三种情况时线程将死亡。

  • run()方法执行结束,线程结束。
  • 线程抛出了一个未捕获的Exception或Error
  • 调用了线程的stop()方法。该方法容易死锁,少用。

注意,死亡状态的线程不能再次调用start()方法来启动,否则会引发异常。

5、线程控制

5.1join线程

举个例子,线程A在执行中调用线程B的join方法,线程A将被阻塞,直到线程B执行完为止。

线程代码如下:

 //通过实现Runnable接口创建线程类

 public class ThreadTwo implements Runnable{

     private int i;

     //run方法同样是线程的执行体

     @Override

     public void run() {

        for (i = 0; i < 5; i++) {

            //实现Runnable接口创建线程类时,只能使用Thread.currentThread()来获取当前线程

            System.out.println(Thread.currentThread().getName()+" "+i);

        }

     }

 }

测试代码如下:

 public class TestThreadJoin {

     public static void main(String[] args) throws InterruptedException {

        ThreadTwo st = new ThreadTwo();

        new Thread(st,"打酱油的线程").start();

        for (int i = 0; i < 10; i++) {

            System.out.println(Thread.currentThread().getName()+" "+i);

            if (i==2) {

               ThreadTwo st2 = new ThreadTwo();

               Thread thread = new Thread(st2,"被join的线程");

               thread.start();

               //main线程调用了thread线程的join方法,必须等thread执行结束才会向下执行

               thread.join();

            }

        }

     }

 }

测试结果如下:

 main 0

 打酱油的线程 0

 main 1

 打酱油的线程 1

 main 2

 打酱油的线程 2

 打酱油的线程 3

 被join的线程 0

 打酱油的线程 4

 被join的线程 1

 被join的线程 2

 被join的线程 3

 被join的线程 4

 main 3

 main 4

 main 5

 main 6

在以上代码中,main线程的i等于2时,启动了“被join的线程”,这时main线程进入阻塞状态,只有“打酱油的线程”“ 被join的线程”在运行,等“被join的线程”运行完了,main线程才重新开始运行。

5.2后台线程

后台线程也称“守护线程”或“精灵线程”。jvm的垃圾回收线程就是典型的后台进程。

一般线程在被创建之后,其生命周期是独立的。而后台进程的生命周期与前台进程相关:当所有前台进程都死亡,后台进程也随之死亡。

使用thread.setDaemon(true)可将线程设为后台线程,且必须在线程启动前设置。

前台线程创建的线程默认为前台线程。

后台线程创建的线程默认为后台线程。

5.3线程睡眠sleep

Sleep方法是Thread类提供的一个静态方法,让当前线程进入阻塞状态,时间到了之后,线程会自动转入就绪状态。

5.4线程让步yield

yield方法和sleep方法类似,也是一个Thread类提供的静态方法,和sleep不同的是,yield是让线程转入就绪状态。

当某个线程调用了yield方法后,和当前线程优先级一样,或更高的线程会转入运行状态。

5.5线程优先级

Thread类提供了setPriority(int newPriority)方法和getPriority()方法来设置和获取线程优先级,优先级的范围通常在1-10之间,10是最高优先级。

不过不同系统的优先级数值可能不同,所以通常推荐使用Thread类的三个静态常量来设置优先级,分别是MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY。

java多线程回顾2:生命周期与控制的更多相关文章

  1. Java多线程——线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  2. Java多线程-线程的生命周期

    线程可以分为4个状态:New(新生),Runnable(可运行):为了方便分析,还可将其分为:Runnable与Running.blocked(被阻塞),Dead(死亡). 与人有生老病死一样,线程也 ...

  3. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]

    原文:WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇] 在[第2篇]中,我们深入剖析了单调(PerCall)模式下WCF对服务实例生命周期的控制,现在我们来 ...

  4. Java 并发 线程的生命周期

    Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用 ...

  5. Java精选笔记_多线程(创建、生命周期及状态转换、调度、同步、通信)

    线程概述 在应用程序中,不同的程序块是可以同时运行的,这种多个程序块同时运行的现象被称作并发执行. 多线程可以使程序在同一时间内完成很多操作. 多线程就是指一个应用程序中有多条并发执行的线索,每条线索 ...

  6. Java基础知识笔记(四:多线程基础及生命周期)

    一.多线程基础 编写线程程序主要是构造线程类.构造线程类的方式主要有两种,一种是通过构造类java.lang.Thread的子类,另一种是通过构造方法实现接口java.lang.Runnable的类. ...

  7. java并发编程基础—生命周期与线程控制

    一.线程生命周期 线程被创建启动以后,他既不是一启动就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞(Bloc ...

  8. 「小程序JAVA实战」小程序视频播放的时候生命周期的控制(56)

    转自:https://idig8.com/2018/09/23/xiaochengxujavashizhanxiaochengxushipinbofangdeshihoushengmingzhouqi ...

  9. Java - JVM - 类的生命周期

    概述 简述 JVM 里 类的生命周期 上次写了 30%, 居然丢了 难受, 又要重新写 类的生命周期 加载 使用 卸载 1. 加载 概述 类型的加载 大体流程 装载 连接 验证 准备 解析(可选的) ...

随机推荐

  1. Java12新特性 -- switch表达式

    传统switch表达式的弊端: 匹配是自上而下的,如果忘记写break, 后面的case语句不论匹配与否都会执行: 所有的case语句共用一个块范围,在不同的case语句定义的变量名不能重复: 不能在 ...

  2. Comparable和Comparator 是什么以及区别

    一.Comparable和Comparator Comparable可以认为是一个内比较器,实现了Comparable接口的类,类的实例与实例直接可以比较,依赖compareTo方法的实现,compa ...

  3. WeCenter3.1.7 blind xxe 分析

    xxe漏洞危害大,可以查看任意文件,执行系统命令,进行ddos等,但是本次漏洞有一条件,需要后台登录,所以危害降低了,下面是详细分析 在models/weixin.php public functio ...

  4. ‎Cocos2d-x 学习笔记(20) ControlButton

    [Cocos2d-x 学习笔记 目录链接] 1. 简介 ControlButton实现了按钮功能,根据触摸的位置和移动的过程可识别9中EventType类型,执行对应的回调函数. 直接继承了Contr ...

  5. 1、Struts2基本入门

    一.了解了这几个主要的优点,会促使你考虑使用Struts2 : 1.POJO表单及POJO操作 - Struts2 去除掉了Struts框架中的Action Forms部分.在Struts2框架下,你 ...

  6. opencv实践::对象的提取

    问题描述 真实案例,对图像中对象进行提取,获取这样对象,去掉其它干扰和非目标对象. 解决思路 二值分割 + 形态学处理 +横纵比计算 #include <opencv2/opencv.hpp&g ...

  7. 1.7.3.1版本ride乱码的解决方法

    现象: 解决方式: 修改文件\Python36\Lib\site-packages\robotide\contrib\testrunner\testrunner.py 将latin1修改为mbcs 然 ...

  8. 每日温度(LeetCode Medium难度算法题)题解

    LeetCode 题号739中等难度 每日温度 题目描述: 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 ...

  9. Linux本地内核提权漏洞复现(CVE-2019-13272)

    Linux本地内核提权漏洞复现(CVE-2019-13272) 一.漏洞描述 当调用PTRACE_TRACEME时,ptrace_link函数将获得对父进程凭据的RCU引用,然后将该指针指向get_c ...

  10. .NET Core System.Drawing.Common 中文乱码的坑

    最近在写一个汉字取点阵的程序,最开始是在win环境下运行的,没发现什么异常,然后今天把程序放在centos 下后发现英文正常,中文完全变成两位的字了,最开始是字体的原因 在把宋体等安装到centos ...