当前课程知识点:JAVA程序设计进阶 >  第二章 线程(中) >  2.5 线程的生命周期与死锁 >  Video

返回《JAVA程序设计进阶》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《JAVA程序设计进阶》慕课在线视频列表

Video课程教案、知识点、字幕

这一节我们将介绍

线程的生命周期与死锁

那一个线程从生到死

都经历很多状态

这也是我们本节

要重点阐述的内容

每个线程它是有它的生命周期的

一个线程从产生到消亡的过程

它会处于多种状态

那这种状态的话

会影响到它的这个

执行的一个过程

我们来看一下这张图

这是我们线程的生命周期状态图

可能我们需要从最右下角开始看

当我们实例化一个线程以后

调用它的start方法

它就会进入一种就绪状态

那英文就叫Runnable状态

那这种状态的话

它不是马上就能运行的

因为它必须由我们线程的调度器

来决定它是否运行

如果线程调度调到它的话

它就会这个进入运行状态

而进入运行状态的话

如果它比较顺利的话

我们往左边看

就运行状态左边

就是它的run方法都运行完了

那这时候它就会自然而然

进入死亡状态

但是在运行过程当中

有可能会碰到

各种各样的这个情况

比如说它调用了

线程调用了wait方法

它需要等待某一个对象

那它就会进入这个

某个对象的等待值

然后整个这时候

我们这个线程

进入了这个阻塞状态

那这个阻塞状态

什么时候这个恢复呢

那其实它就会被别的线程

调用了notify这个方法

调用notify通知它了以后

它就会进入这个

另外一种阻塞状态

也就是进入对象的

这个锁的这个池

那实际上当我们在运行状态时候

如果是调用了synchromized

这个这样的同步方法

但是你又没等到那个锁的时候

你一样也会进入这个阻塞状态

进入到等待某个对象的

锁的这么一个池子当中

那当你进入这个

某个对象的锁的池当中的时候

你又获得了锁的话

你就会返回到这个就绪状态

返回到就绪状态的话

又会等待

我们线程调度器的这个调度

那在运行状态的同时

我们如果大家往左下角看的话

如果看调用了sleep这个语句

那你自己就会进入一个休眠状态

休眠状态当你的休眠时间

结束的时候

那你这个线程就会进入

这个就绪状态

然后又继续等待

我们线程的调度

所以对于一个线程的话

它是有它的生命周期的

那这里面的几种状态

我们再做进一步的解释

一开头是诞生状态

也就是说线程刚刚被创建出来

也就是刚刚new出来

它就是一个诞生状态

那紧接着又进入了就绪状态

那也就是指

我们调用了线程的start方法

那这时候它就这个

进入就绪状态

进入就绪状态

线程自己都已经准备好了

就差CPU

这时候由我们的线程调度器

来去决定什么时候

把CPU分配给它

然后当CPU分给它的时候

那我们的线程

就进入了运行状态开始执行

当开始执行的话

执行如果运气好

比较顺利的话它就会执行结束

就进入死亡状态

那在执行过程中

有可能会发生各种阻塞状态

就是Blocked状态

那什么情况下会发生阻塞状态呢

比如说线程它需要进行

输入输出的访问

但是又必须等待 举个例子

比如说我们线程执行过程中

想接受用户的一个键盘输入

结果正好用户不在

用户出去了 迟迟不按键盘

那这个时候就会进入阻塞状态

那另外一种进入阻塞状态

可能是当我们

这个调用了同步方法

但是我们这同步方法

我又没能获得

所对应的对象的锁

所以我这个线程

就只能进入阻塞状态

再一个阻塞状态

有可能就是我这个线程

等候一个某一个条件变量

然后调用了wait方法

就一直在等待

所以线程也进入了阻塞状态

再下一个状态就是休眠状态

也就是我们线程

主动执行sleep方法

而进入了休眠

最后一个状态就是死亡状态

也就是说我们线程

自己运行结束 然后退出

然后我们线程就死亡了

现在我们介绍一下死锁问题

死锁只是什么呢

就是说我们线程在运行过程当中

其中的某个步骤

往往需要满足一些条件

才能够继续运行下去

如果这个条件不能满足

那线程就在这个步骤上

出现了这个阻塞

那往往有多个线程在一起的时候

互相等待的话

就会出现很大的麻烦

比如说线程A

可能说要等待线程B

而线程B要等待线程C

依此类推最后一个线程

又要去等待线程A的某个对象

或某个东西

这样的话变陷入了

彼此等待的轮回当中

任何线程都动弹不得

这样就陷入了所谓的死锁

那对于死锁问题的话

我们的关键就在于

就是要怎么去预防它

下面给大家举一个例子

比如说这是一个游戏

有三个人

站在三角形的三个顶点

三条边旁边各自有一个球

总共三个球

要求我们这三个人

首先拿到自己左手边的球

才能去拿它去右手边的球

然后两个手都有球

都拿到了以后

才能把这两个球放下

这是一个简单的游戏

那我们看怎么写程序

来去模拟它

我们先看第一个类

第一个类里面的主方法

我们构造了一个球的对象

Balls ball=new Balls

然后我们构造了三个游戏者对象

Player0 Player1

Player2

分别调用它们的构造方法

进行实例化

而且并且把同样一个球对象

当做这个参数传递给它们

紧接着这三个游戏者线程

我们都给它启动

调用它start方法

再往下我们看看

我们的球类Balls

那里面有一个标志

boolean flag0=false

表示0号球这个被人拿起

就是说true表示拿起

false表示放下

紧接着第二个标志

flag1是false

表示这个1号球的

这个初始状态是没被人拿起

然后boolean flag2

也是等于false 然后没被拿起

下面我们看一下这个Player0

0号游戏者的类

它extends Thread

它是个线程

然后这里面它有个成员变量ball

然后它构造方法

就是把这个ball传进来

我们再看它的这个run方法

run方法里面

首先是一个这个无限循环

while true

那里面什么逻辑呢

第一while ball.flag1=true

如果1号球被人拿走

它就一直在等

如果等到了它就拿起1号球

它就把ball.flag1设置为true

设置为(争)

就表明说我拿到这个球了

然后紧接着它又想

因为我们刚才游戏规则

先拿左手的球

那对于Player0的话

它左手的球就是这个1号球

那现在它要拿它右手的球了

那就是这个正好是0号球

所以它又在等待

也就是while ball.flag0=true

也就是被别人拿走了 没放下

所以它一直等

等的话如果有人放下的时候

它就能拿到了

那这时候它就写的

if ball.flag1=true

并且这个ball.flag0=false

然后它就会把0号球给拿起来

把右手边的球拿起来

所以ball.flag0设置为true

然后紧接着打印出来说

我两个球都拿到了

Player0 has got two balls

然后紧接着它把这个

两个球都往下放

那怎么往下放呢

就是ball.flag1设为false

ball.flag0设为false

然后紧接着这个try sleep1

就休眠1毫秒

所以我们看到这个

Player0这个线程的话

在它的这个run方法里面

就是模拟的拿球和放球的过程

它先拿起它左手边的球

也是1号球

但拿着它得等待

如果必须是那个

是没有被别人拿走那才能拿

拿到以后接着

它就拿到右手边的球

就是0号球

那拿之前也必须要等待

必须等待有别人把球放下来

那假设这两个球它都拿到了

然后紧接着它就把两个球

都共同放下

放下过程就把这两个球都

它的状态都设置成为false

那这个是我们第一个游戏者的

它的代码

那我们看第二个游戏者

实际上就是1号游戏者

那1号游戏者的话也是依此类推

和刚才我们那个0号游戏者的

这个代码逻辑是很像的

只不过是说他左手边

和右手边的这个球的编号

不太一样

比如说我们看我们这个run方法

这个run方法里面

它首先就需要

它的左手边的球就是0号球

所以它得等0号球的标志

属于false它才能去拿

一旦有人作为

把那个0号球的标志

作为false的话

它就把它拿起来

它一拿起它就把这个设置为true

0号球的标志设置为true

然后紧接着它又等待

它右手边这个球

右手边的球就是

标志就是这个flag2

也在进行这个等待别人放下来

那最后的话

当它左右手的球都拿到了以后

它会把这两个球都往下放

往下放那就是

把这个flag0和flag2的这个标志

都设为false

好 再紧接着看一下

这个第二号游戏者

那第二号游戏者的这个代码逻辑

和刚才前两个是类似的

只不过就是它所对应的这个

左手的球和右手的球的

这个编号不一样

大家仔细看一下

也能看出来它的这个区别

和前面的类似的地方

好 就这么样一个程序

我们运行它

运行若干次以后

就会这个陷入死锁的状态

没有任何信息输出

也就是说任何一个玩家

都不能同时拥有两侧的球

为什么呢

因为如果这三个玩家

恰好每人都拿起它左手边的球

然后都在等待它右手边的球

那由于这个三个玩家

它都必须等到它拿到两个球

它才能把它两个全部往下放

那这个时候相当于每个人

手中只有一个球

然后拿不到两个球

所以它也不会

把它已经拿到的那一个球往下放

所以这三个线程

互相的这个等待

这样的话导致我们这几个线程

陷入了死锁状态

那一会儿我们为了便于观察

死锁发生条件

我们可以在每个线程下面

这个放下两边球

增加这个sleep语句

大家可能会看得更加清楚

那如果我们想避免死锁的话

怎么办呢

那就需要修改游戏规则

比如说我们每个人

只能抢这个

自己两侧这个球中

这个球号比较小的球

抢到了小的球

球号小的球才能拿另外一个球

这样一个规定的话

就会避免死锁的出现

而我们在控制线程的过程当中

一般来说如果想

结束一个线程的生命的话

是推荐大家让我们的run方法

正常运行结束

这样的话就能够

使一个线程的生命

进入一个死亡状态

在线程的API当中

体规了stop方法

来去可以结束线程的生命

但是如果只用stop方法的话

有可能会影响数据的操作

导致数据的不完整性

因此我们不提倡用stop方法

来去结束线程的生命

而是希望说在这个run方法

让它自动执行完

或者我们在run方法中

去设置一些循环条件

通过变更这个循环条件

使得这个run方法能够结束

所以这是我们控制线程的

生命周期的一个办法

这一节我们介绍了

线程的生命周期和死锁

通过恰当的控制线程的生命周期

我们可以有效的避免死锁

JAVA程序设计进阶课程列表:

第一章 线程(上)

-1.0 导学

--Video

-1.1 线程的基本概念

--Video

-1.1 线程的基本概念--作业

-1.2 通过Thread类创建线程

--Video

-1.2 通过Thread类创建线程--作业

-1.3 线程的休眠

--Video

-1.3 线程的休眠--作业

-1.4 Thread类详解

--Video

-1.5 通过Runnable接口创建线程

--Video

-1.5 通过Runnable接口创建线程--作业

-1.6 线程内部的数据共享

--Video

第二章 线程(中)

-2.0 导学

--Video

-2.1 线程同步的思路

--Video

-2.2 线程同步的实现方式—Synchronization

--Video

-2.3 线程的等待与唤醒

--Video

-2.4 后台进程

--Video

-2.5 线程的生命周期与死锁

--Video

-2.6 线程的调度

--Video

第三章 线程(下)

-3.0 导学

--Video

-3.1 线程安全与线程兼容与对立

--Video

-3.2 线程的安全实现-互斥同步

--Video

-3.3 线程的安全实现-非阻塞同步

--Video

-3.4 线程的安全实现-无同步方案

--Video

-3.5 锁优化

--Video

第四章 网络编程(上)

-4.0 导学

--Video

-4.1 URL对象

--Video

-4.2 URLConnection对象

--Video

-4.3 Get请求与Post请求

--Video

-4.4 Socket通信原理

--Video

-4.5 Socket通信实现

--Video

第五章 网络编程(下)

-5.0 导学

--Video

-5.1 Socket 多客户端通信实现

--Video

-5.2 数据报通信

--Video

-5.3 使用数据报进行广播通信

--Video

-5.4 网络聊天程序

--Video

第六章 Java虚拟机

-6.0 导学

--Video

-6.1 Java虚拟机概念

--Video

-6.2 Java虚拟机内存划分

--Video

-6.3 Java虚拟机类加载机制

--Video

-6.4 判断对象是否存活算法及对象引用

--Video

-6.5 分代垃圾回收

--Video

-6.6 典型的垃圾收集算法

--Video

-6.7典型的垃圾收集器

--Video

第七章 深入集合Collection

-7.0 导学

--Video

-7.1 集合框架与ArrayList

--Video

-7.2 LinkedList

--Video

-7.3 HashMap与HashTable

--Video

-7.4 TreeMap与LinkedHashMap

--Video

-7.5 HashSet

--Video

第八章 反射与代理机制

-8.0 导学

--Video

-8.1 Java反射机制

--Video

-8.2 Java静态代理

--Video

-8.3 Java动态代理

--Video

-8.4 Java 反射扩展-jvm加载类原理

--Video

-8.5 Java进阶课程总结

--Video

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。