多线程的几种状态
新建 就绪 运行 阻塞 死亡
- 新建:
线程被创建出来 - 就绪:
具有CPU的执行资格, 但是不具有CPU的执行权 - 运行:
具有CPU的执行资格, 也具有CPU的执行权 - 阻塞:
不具有CPU的执行资格, 也不具有CPU的执行权 - 死亡:
不具有CPU的执行资格, 也不具有CPU的执行权
线程的阻塞状态
上一篇有说过sleep可以使线程处于阻塞状态,今天要说的 wait() 方法也可以使线程处于阻塞状态。首先来看一下这两个方法的区别;
-
共同点:
wait()方法和sleep()方法 都可以使线程处于阻塞状态
都可以设置线程的阻塞时间 -
不同点:
wait() 可以设置时间量,也可以不设置。
sleep() 是要必须要设置休眠的时间
wait() 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法;sleep()不一定要获得锁。
sleep() 休眠不会释放锁
wait() 一旦等待就会释放锁,让出cpu的执行权,直到当 notify/notifyAll() 被执行时候,才会被唤醒然后继续往下执行
wait() 阻塞状态的唤醒
当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。
1. notify/notifyAll() 这两种方法的区别
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。
notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行。
2. notify/notifyAll() 执行了之后是立刻就释放锁吗?
不是的;当 notify/notifyAll() 被执行之后,就会唤醒对应所对象的一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,才会再次释放锁。
也就是说,notify/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁,锁的释放要看代码块的具体执行情况。所以在编程中,尽量在使用了notify/notifyAll() 后立即退出临界区,以唤醒其他线程 。
3. 使用wait()和notify/notifyAll()实现生产者和消费者问题
- 生产者和消费者问题是什么?
首先来举一个例子,你去大郎烧饼店买包子吃,大郎说包子没有了你先等一会儿,我这就让金莲给你做两个来,你等了五分钟烧饼出炉了,你终于吃到了烧饼。
生产者和消费者模型基本原理也是这样,生产者产生消费者所需要的资源,并存在缓冲区;消费者消耗缓冲区中的资源,前提是缓冲区中有所需要的资源,如果缓冲区中没有需要的资源,那么消费者就停止处于等待状态,并通知生产者生产资源; - 代码演示
现有一个学生类,该类的属性包括姓名和年龄;需求:由生产者设置学生对象的属性,消费者打印出生产者所设置的学生对象的姓名和年龄
- 测试程序
public class MyTest {
public static void main(String[] args) {
Student student = new Student();
//生产者线程
SetThread setThread = new SetThread(student);
//消费者线程
GetThread getThread = new GetThread(student);
getThread.start();
setThread.start();
}
}
- 学生类
public class Student {
public String name;
public int age;
//设置一个标记
public boolean flag = false; //默认值false 代表没有资源,true 代表有资源
}
- 生产者:
public class SetThread extends Thread {
Student student;
int i = 0;
public SetThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true) {
synchronized (student) {
if (student.flag) {
//作为生产者,如果有资源了
try {
student.wait(); //等着
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//在生产资源
if (i % 2 == 0) {
student.name = "张三";
student.age = 23;
} else {
student.name = "李四";
student.age = 24;
}
//修改标记
student.flag = true;
student.notify();//通知消费者去消费,唤醒之后,两个线程还得抢时间片
i++;
}
}
}
}
- 消费者
public class GetThread extends Thread {
Student student;
public GetThread(Student student) {
this.student = student;
}
@Override
public void run() {
while (true) {
synchronized (student) {
if (!student.flag) {
//没有资源作为消费者,等着
try {
student.wait(); //一旦等待,就会释放锁,等待后,被唤醒,就从这里醒来
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有了资源,你消费
System.out.println(student.name + "===" + student.age);
//修改标记
student.flag = false;
student.notify();
}
}
}
}