一、线程生命周期

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

1、新建状态

当程序使用new关键字创建了一个线程后,该线程就处于新建状态

2、就绪状态

当线程对象调用了start()方法之后,该线程就处于就绪状态,java虚拟机会为其创建方法调用栈和程序计数器。

这个状态中的线程并没有开始执行线程,只是表示该线程可以运行了,至于何时运行,取决于JVM线程调度器调度。

3、运行状态

如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。

4、阻塞状态

当运行状态的线程发生如下情况时,线程会进入阻塞状态:

(1)线程调用sleep()方法主动放弃所占用的处理器资源。

(2)线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞

(3)线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。

(4)线程在等待某个通知(notify)

(5)程序调用了线程的suspend()方法将线程挂起,这个方法在jdk1.6中已经过时,它容易导致死锁,不建议使用。

针对上面阻塞状态,当发生下面特定情况可以解除阻塞状态:

(1)sleep()方法经过了指定时间。

(2)阻塞式IO方法已经返回

(3)线程成功获得了一个同步监视器。

(4)线程在等待某个通知时,其他线程发出了一个通知

(5)处于挂起的线程被调用了resume()恢复方法

5、线程死亡

线程结束后就处于死亡状态,有三种结束方式:

(1)run()或call()方法执行完成,线程正常结束

(2)线程抛出一个未捕获的Exception或者Error

(3)直接调用线程的stop()方法结束线程——容易死锁,不建议使用

isAlive()方法可以判断线程是否死亡,当处于就绪、运行、阻塞状态时返回true,处于新建、死亡状态时返回false。

已经死亡的线程不能重新启动,否则引发IllegalThreadStateException。

二、控制线程

java线程提供了一些简便的工具方法,利用这些方法可以很好的控制线程

1、join()

join()方法:让一个线程等待一个线程完成。

  1. package threadtest;
  2. public class ThreadTest implements Runnable {
  3. @Override
  4. public void run() {
  5. for(int i=0;i<30;i++) {
  6. System.out.println(Thread.currentThread().getName() + " " + i);
  7. }
  8.  
  9. }
  10.  
  11. public static void main(String[] args) throws InterruptedException {
  12.  
  13. ThreadTest target1 = new ThreadTest();
  14. Thread t1 = new Thread(target1,"t1");
  15. t1.start();
  16. for(int i=0;i<30;i++) {
  17. System.out.println(Thread.currentThread().getName() + " " + i);
  18. //开始主线程和t1线程并发执行,当main线程的i到15时,调用了t1线程的join方法,
  19. //此时主线程等待t1线程,直到t1结束时才跑main,
  20. //join后,主线程处于阻塞状态
  21. if(i == 15) {
  22. t1.join();
  23. }
  24. }
  25. }
  26.  
  27. }

2、线程睡眠 sleep()

如果需要让当前线程暂停一段时间,则可以使用sleep()方法

  1. package threadtest;
  2.  
  3. import java.time.LocalTime;
  4.  
  5. public class ThreadTest implements Runnable {
  6.  
  7. @Override
  8. public void run() {
  9. for(int i=0;i<30;i++) {
  10. System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
  11. if(i == 15){
  12. try {
  13. Thread.sleep(10000);//10s
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }
  19. }
  20.  
  21. public static void main(String[] args) throws InterruptedException {
  22.  
  23. ThreadTest target1 = new ThreadTest();
  24. Thread t1 = new Thread(target1,"t1");
  25. t1.start();
  26. }
  27. }

3、线程让步 yield()

yield()方法会让线程直接进入就绪状态,主要作用就是让当前线程暂停一下。完全有可能线程yield()后,线程调度器又将该线程调度出来执行。

yield()暂停后,只有优先级与当前线程相同或者优先级比当前线程更高的处于就绪状态的线程才有机会获得执行机会。

  1. package threadtest;
  2.  
  3. import java.time.LocalTime;
  4.  
  5. public class ThreadTest implements Runnable {
  6. @Override
  7. public void run() {
  8. for(int i=0;i<30;i++) {
  9. System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
  10. if(i == 15){
  11. Thread.yield();//线程让步
  12. }
  13. }
  14. }
  15.  
  16. public static void main(String[] args) throws InterruptedException {
  17.  
  18. ThreadTest target1 = new ThreadTest();
  19. Thread t1 = new Thread(target1,"t1");
  20. t1.start();
  21. for(int i=0;i<10;i++) {
  22. System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
  23. }
  24. }
  25. }

sleep()和yield()方法的区别

(1)sleep暂停后会给其他线程机会,不会理会其他线程的优先级,但yield只给优先级相同或者更高的线程机会

(2)sleep将线程转为阻塞状态,yield将线程转为就绪状态

(3)sleep方法声明抛出了InterruptedException异常,所以用sleep要么捕捉该异常,要么抛出该异常。

(4)sleep比yield有更好的移植性,通常不建议使用yield方法来控制并发线程的执行

线程的优先级

每个线程执行时都有一定的优先级,优先级高的线程能获得更多的执行机会。每个线程的默认优先级与创建它的父线程优先级相同。默认情况下,main线程具有普通优先级

Thread类中 setPriority(int newPriority)和getPriority()方法分别设置和获取线程的优先级。

setPriority(int newPriority)的参数是一个整数,范围1-10;也可以是三个静态常量

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

  1. package threadtest;
  2.  
  3. import java.time.LocalTime;
  4.  
  5. public class ThreadTest implements Runnable {
  6. @Override
  7. public void run() {
  8. for(int i=0;i<30;i++) {
  9. System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
  10. if(i == 15){
  11. Thread.yield();
  12. }
  13. }
  14. }
  15.  
  16. public static void main(String[] args) throws InterruptedException {
  17.  
  18. ThreadTest target1 = new ThreadTest();
  19. Thread t1 = new Thread(target1,"t1");
  20. Thread t2 = new Thread(target1,"t2");
  21. t2.setPriority(Thread.MAX_PRIORITY);//设置优先级
  22. t1.start();
  23. t2.start();
  24. }
  25. }

java并发编程基础—生命周期与线程控制的更多相关文章

  1. Java并发1——线程创建、启动、生命周期与线程控制

    内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...

  2. Java并发编程基础

    Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...

  3. 并发-Java并发编程基础

    Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...

  4. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  5. Java并发编程--基础进阶高级(完结)

    Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...

  6. Java并发编程(您不知道的线程池操作)

    Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...

  7. 【Java并发编程】之二:线程中断

    [Java并发编程]之二:线程中断 使用interrupt()中断线程 ​ 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...

  8. java并发编程笔记(七)——线程池

    java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...

  9. java并发编程笔记(五)——线程安全策略

    java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...

随机推荐

  1. GStreamer跨平台多媒体框架

    GStreamer跨平台多媒体框架 Gstreamer基本概念 GStreamer是用于构造媒体处理组件图的库.它支持的应用程序范围从简单的Ogg / Vorbis回放,音频/视频流到复杂的音频(混合 ...

  2. 预测汽车级Linux专业技术的需求

    预测汽车级Linux专业技术的需求 Anticipating need for Automotive Grade Linux expertise 在听了多年汽车级Linux(AGL)及其所有潜力之后, ...

  3. java后端知识点梳理——JVM

    可以先看看我的深入理解java虚拟机笔记 深入理解java虚拟机笔记Chapter2 深入理解java虚拟机笔记Chapter3-垃圾收集器 深入理解java虚拟机笔记Chapter3-内存分配策略 ...

  4. 02:HTML

    HTML介绍 Web服务本质 import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk.listen(5 ...

  5. 关于Maven repository中pom.xml的jar包依赖

    https://mvnrepository.com 该mvn网站可以找到个个版本的依赖jar包  http://doc.canglaoshi.org 该网站为达内的开发文档服务器,可以找到很多开发中需 ...

  6. 【模拟8.03】数颜色(vector//主席树)

    才知道vector在插入值后是可以直接修改的... 那就很简单了 用vector的lowerbound这样的二分操作,提前储存每个颜色的位置 发现交换相对位置不变 关于vector的lowerboun ...

  7. noip2012 总结

    Vigenère 密码 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密码.Vigenère 密码的加密解密算法简单易用,且破译 ...

  8. Vue(12)组件的组织结构和组件注册

    组件的组织 通常一个应用会以一棵嵌套的组件树的形式来组织: 例如,你可能会有页头.侧边栏.内容区等组件,每个组件又包含了其它的像导航链接.博文之类的组件. 为了能在模板中使用,这些组件必须先注册以便 ...

  9. Java 读取Word表格中的文本和图片

    本文通过Java程序来展示如何读取Word表格,包括读取表格中的文本和图片.下面是具体实现的步骤和方法. 1. 程序环境准备 代码编译工具:IntelliJ IDEA Jdk版本:1.8.0 测试文档 ...

  10. NuGet微软官方中国镜像地址

    https://nuget.cdn.azure.cn/v3/index.json