什么是多线程?多线程API详解

本文详细介绍了线程的概念、创建方式、生命周期及其状态转换,深入探讨了Thread类的各种方法,包括sleep、yield、interrupt等,以及如何管理和关闭线程。

目录

1、多线程基础

1.1 什么是线程

1.2 创建线程

1.3 线程的生命周期

1.3.1 线程的NEW状态

1.3.2 线程的RUNNABLE状态

1.3.3 线程的RUNNING状态

1.3.4 线程的BLOCKED状态

1.3.5 线程的TERMINATED状态

1.4 Thread模拟营业厅叫号机程序

1.5 守护线程

2、Thread APA的信息介绍

2.1 线程sleep

2.2 线程yield

2.3 设置线程优先级

2.4 获取线程ID

2.5 获取当前线程

2.6 设置线程上下文加载器

2.7 线程interrupt

2.8 线程join

2.9 关闭线程

2.9.1 正常关闭

2.9.2 异常退出

2.9.3 进程假死

 


1.1 什么是线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每个线程执行不同的任务。

特点:轻型实体、独立调度和分派的基本单位、可并发执行、共享进程资源

1.2 创建线程

创建线程的两种方法:1 实现Runnable接口并从写run方法;2 集成Thread类并重新run方法。

实现Runnable接口:

image.png

 

集成Thread类:

image.png

 

1.3 线程的生命周期

线程的什么周期大致可以分为五个阶段:1、new(新建) 2、Runnable(就绪) 3、Running(运行) 4、Blocked(阻塞) 5、Terminated(结束)

1.3.1 线程的NEW状态

当我们使用关键字new创建一个Thread对象时,此时他并不处于执行状态,因为没有调用start的方法启动该线程,那么线程的状态为New状态。NEW状态只有通过start方法进入RUNNABLE(就绪状态)状态。

1.3.2 线程的RUNNABLE状态

线程对象进入RUNNABLE(就绪状态)必须调用start方法,那么此时才真正的在JVM进程中创建了一个线程,线程的运行与否都要由CPU的调度,那么我们把这个中间转态成为可执行状态,就是已经就绪,但是没有真正的执行起来。

1.3.3 线程的RUNNING状态

一旦CPU通过轮询或者其他方式从任务可执行队列中选中了线程,那么此时他才能真正的执行自己的逻辑代码。在该状态下,线程可以发生如下状态切换:

1)直接进入TERMINATED状态,比如调用了JDK已经不推荐使用的stop方法或者判断某个逻辑标识。

2)进入BLOCKED状态,比如调用sleep,或者wait方法进入waitSet中

3)进入某个阻塞的IO操作,比如因网络数据的读写进入了BLOCKED状态

4)获取某个锁资源,从而加入到该锁的阻塞队列中而进入BLOCKED状态

5)由于CPU的调度器轮询是该线程放弃执行,进入RUNNABLE状态

5)线程主动yield(线程让步)方法,放弃CPU执行权,进入RUNNABLE状态

1.3.4 线程的BLOCKED状态

就是由1.3.3线程的RUNNING状态进入BLOCKED状态

在该状态下,线程可以发生如下状态切换:

1)直接进入TERMINATED状态,比如调用了JDK已经不推荐使用的stop方法或者判断某个逻辑标识。

2)线程阻塞的操作结束,进入到RUNNABLE状态

3)线程完成休眠,进入RUNNABLE状态

4)wait中的线程被其他线程的notify/notifyall唤醒,进入RANNABLE状态

1.3.5 线程的TERMINATED状态

线程的TERMINATED状态是一个线程的最终状态,该状态不会再切换到任何状态,进入此状态就意味着该线程的整个生命周期都结束了。

1.4 Thread模拟营业厅叫号机程序

程序如下:

image.png

 

1.5 守护线程

什么是守护线程:

JVM在没有一个非守护线程运行时,JVM将会退出。守护线程拥有自己结束自己生命周期的特性,而非守护线程没有。JVM的垃圾回收线程就是典型的守护线程,在垃圾回收结束后自动结束生命周期。

2、Thread APA的信息介绍

2.1 线程sleep

sleep是一个静态方法,其有两个重载方法,起重一个需要传入毫秒数,另一个既需要毫秒也需要纳秒数。

使用Thread.sleep()方法就能把当前线程进入指定的时间进行休眠。

使用TimeUnit替代Thread.sleep

JDK1.5之后就引入了一个枚举TimeUnit,是对sleep的封装,我们使用sleep要对时间进行换算,TimeUnit就省去了这一步骤。例如想让程序休眠2小时24分钟12秒44毫秒

TimeUnit.HOURS.sleep(2);  //小时

TimeUnit.MINUTES.sleep(24); //1分钟

TimeUnit.SECONDS.sleep(12);  //秒

TimeUnit.MILLISECONDS.sleep(44);  //毫秒

sleep和wait的区别:

1)sleep是Thread的方法,而wait是Object的方法

2)wait方法的执行必须在同步的方法中进行,而sleep则不需要

3)线程在同步方法中执行sleep方法时,并不会释放monitor锁,而wait方法则会释放monitor的锁

4)sleep方法短暂休眠之后会主动退出阻塞,而wait方法则需要被其他线程中断后才能退出

2.2 线程yield

yield方法属于启发式的方法,其会提醒调度器我愿意放弃当前CPU的资源,如果CPU的资源不紧张,则会忽略这种提醒。yield方法不是每次都生效的。

sleep和yield的区别:

sleep会导致当前线程暂停指定的时间,没有CPU的消耗,几乎百分百的完成了给定的时间休眠,而yield则不会。

yield只是对CPU的调度器的一个提示,如果CPU没有忽视,会导致上下文的切换。

2.3 设置线程优先级

线程的优先级比较高会优先获取CPU的调度,但是事实往往不会如你所愿,当CPU比较忙时,设置优先级可能会获得更多的CPU时间片,但是闲时优先级的高低几乎不会有任何作用。

setPriority() 设置优先级 getPriority() 获取当前线程的优先级

2.4 获取线程ID

public long getId() 获取线程的唯一ID

2.5 获取当前线程

public static native Thread currentThread() 用于返回当前线程的引用

2.6 设置线程上下文加载器

getContextClassLoader() 获取线程上下文的类加载器,简单的来说就是这个线程是有哪个加载器加载的。

setContextClassLoader() 设置该线程的类加载器,这个方法可以打破java类加载器的父委托机制。

2.7 线程interrupt

如下方法的调用可以使当前线程进入阻塞状态,而调用interrupt方法可以打断阻塞。

1)OBject的wait方法

2)OBject的wait(long)方法

3)OBject的wait(long,int)方法

4)Thread的sleep(long)方法

5)Thread的sleep(long,int)方法

6)Thread的join方法

7)Thread的join(long)方法

8)Thread的join(long,int)方法

9)InterruptibleChannel的io操作

10)Selector的wakeup方法

一个线程调用了另一个被阻塞线程的interrupt方法,则会打断阻塞,打断阻塞并不等于该线程的生命周期结束了,仅仅是打断了当前线程的阻塞状态。

2.8 线程join

某个A线程join,会使当前线程B进入等待状态,直到线程A结束生命周期或者达到给定的时间,此时B处于BLOCKED状态。

2.9 关闭线程

2.9.1 正常关闭

1、线程结束生命周期正常关闭,线程运行结束或者完成了自己的使命就会正常退出

2、捕获中断信号关闭线程,在线程里通过标识来中断线程

3、使用volatile开关控制,使用volatile修饰的开关flag关闭线程也是一种常用的方法

2.9.2 异常退出

一个线程的执行单元中是不予许抛出checked异常的,不论是Thread中的run方法还是Runnable中的run方法,如果运行中过程中需捕获checked异常并且判断是否还有运行下去的必要,那么此时可以将checked异常封装成unchecked异常抛出进而结束线程的生命周期

2.9.3 进程假死

所谓进程假死就是虽然进程存在,但是没有日志输出,程序不进行任何作业,看起来就想死了一样,但事实上他没有死,程序之所以出现这样的情况,绝大多数的原因是某个线程阻塞了,或者线程出现了死锁的情况。

 

本文是参考 多线程与高并发编程 一书所做的笔记,都是精简过后的干货,希望对大家有帮助。后续会继续更新 线程安全与同步、线程池原理、线程间的通信等相关文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值