目录
一 线程的6种状态
1 新建状态:new Thread(),new Thread子类() → 尚未启动的线程
调用start()方法之后,就开启了线程,这时线程分为 运行状态 和 阻塞状态.
2 运行状态:线程抢到了CPU执行权的
3 阻塞状态:线程没抢到CPU执行权的
运行状态 和 阻塞状态 可以相互转换
运行状态 和 阻塞状态 都有cpu的执行资格
4 死亡状态:run()方法执行结束,或者调用了stop(),或者发生了异常,线程就死亡了.
stop()方法:强制停止一个正在运行的线程,无论此时线程是何种状态
5 睡眠(休眠)状态:线程调用了sleep(long)或wait(long)方法 → 休眠状态过时间了,可以自己醒过来
6 无限等待状态(植物人状态):线程调用了wait()方法并且没有传参数 → 自己醒不过来,只能调用notify()方法来唤醒无限等待状态
无限等待状态 和 睡眠状态 称为 冻结状态.
二 无限等待wait()、唤醒notify()案例详解
2.1 案例介绍
顾客去买包子,包子可能没有要现做,
但是不知道要多久才能做好,因为不知道顾客要等待的时间,所以调用了wait()方法,此时顾客属于无限等待状态
包子做好了,老板通知顾客包子好了,notify()一下
wait()方法和notify()方法都是object类的方法
notify()之后,会继续执行wait()方法之后的代码
notify()是随机唤醒一个线程,notifyAll()唤醒所有线程
注意:
老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
锁对象必须是唯一的
只有锁对象才能调用wait()方法和notify()方法
2.2 代码
package threadState;
public class WaitAndNotify {
public static void main(String[] args) {
//锁对象必须是唯一的
final Object obj = new Object();
//创建一个顾客线程
new Thread(){
@Override
public void run() {
while (true){
//老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
synchronized (obj){
System.out.println("顾客说要1个素馅的1个肉馅的包子");
//无限等待
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后的代码
System.out.println("包子已经做好了,开吃");
System.out.println("______________________________");
}
}
}
}.start();
//创建一个老板线程
new Thread(){
@Override
public void run() {
while(true){
//花了3S做包子
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//老板和顾客线程要用同步代码块包裹,保证只能实行其中的一个
synchronized (obj){
System.out.println("老板花3S做好了包子");
obj.notify();
}
}
}
}.start();
}
}
运行效果
三 wait(long)和sleep(long)
都是设置倒计时结束后,线程就会自动醒来,线程醒来后变成运行或阻塞状态
sleep(long)是Thread的方法
wait(long)是object方法,wait(long)设置睡眠时间,也可以用notify()或者notifyAll()提前唤醒线程
四 线程之间的通信(等待唤醒机制)
为什么要处理线程之间的通信?
因为多线程并发执行时,默认情况下CPU是随机切换线程的,当我们需要多个线程共同完成一件任务时,
并且希望他们有规律的执行,那么多线程之间需要一些通信,来帮助我们完成多线程共同操作同一份数据.
如何保证线程之间可以有效利用资源?
等待唤醒机制 (避免多个线程对同一共享资源的争夺)
无限等待wait()、唤醒notify()案例升级
等待唤醒机制
重点:有效利用资源 (生产一个包子,吃一个包子)
流程:
包子是共享资源,不能一边生产一个包子一边吃这个包子,作为锁对象
1 有包子的时候(flag==true):
包子铺等着wait() → 吃货吃包子 → 包子吃完了 flag==false → 通知包子铺 notify() → 吃货等着wait() ,
2 没有包子的时候(flag==false):
吃货等着wait() → 包子铺生产包子 → 包子生产好了 flag==true → 通知吃货 notify() → 包子铺等着wait()
代码
包子类
package threadWaitAndNotify;
public class Baozi {
String kind; //包子种类
Boolean flag = false; //false 没有包子,true 有包子
}
包子铺类
package threadWaitAndNotify;
import androidx.annotation.Nullable;
public class BaoziShop extends Thread{
//共享资源包子作为锁对象
private Baozi baozi;
public BaoziShop(Baozi baozi) {
this.baozi = baozi;
}
@Override
public void run() {
int count = 0;
while (true) {
synchronized (baozi){
if(baozi.flag){
//1 有包子的时候
//包子铺不用做包子
try {
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//2 没有包子的时候会被唤醒,走wait()之后的代码
//被唤醒之后,包子铺生产包子
//增加趣味性,生产两种包子
if(count%2==0){
//如果是count是偶数
baozi.kind = "素馅包子";
}else{
//如果是奇数
baozi.kind = "鲜肉大包";
}
count++;
System.out.println("包子铺正在生产"+baozi.kind);
//生产包子需要3秒钟
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//生产好包子之后,修改状态为有
baozi.flag =true;
//通知吃货吃包子
baozi.notify();
}
}
}
}
吃货类
package threadWaitAndNotify;
import androidx.annotation.Nullable;
public class Chihuo extends Thread{
//共享资源包子作为锁对象
private Baozi baozi;
public Chihuo( Baozi baozi) {
this.baozi = baozi;
}
@Override
public void run() {
while (true) {
synchronized (baozi){
if(!baozi.flag){
//如果没有包子就等待
try {
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有包子的时候
//被唤醒之后,有包子了,吃货可以吃包子了
System.out.println("吃货正在吃"+baozi.kind+"的包子");
System.out.println("吃货吃完了"+baozi.kind+"包子");
//吃完包子,包子没有了
baozi.flag= false;
//通知包子铺生产包子
baozi.notify();
System.out.println("------------------------------");
}
}
}
}
测试类
package threadWaitAndNotify;
public class Ceshi {
public static void main(String[] args) {
Baozi baozi = new Baozi();
new BaoziShop(baozi).start();;
new Chihuo(baozi).start();
}
}
效果:
注意:
1 wait()与notify()方法必须由同一个锁对象调用
2 wait()与notify()方法属于object类
3 wait()与notify()方法必须在同步代码块或同步方法中使用,因为必须由锁对象来调用这两个方法