一,线程的五种状态
1,NEW:至今尚未启动的线程处于这种状态。
2,RUNNABLE: 正在Java虚拟机上运行的线程处于这种状态。
3,BLOCKED:阻塞状态,受阻塞并等待某个监视器锁的线程处于这种状态。
4,TIMED_WAITING:休眠(睡眠)状态,计时等待。
5,WAITING:无限期等待另一个线程来执行某一特定操作(notify)的线程处于这种状态。
6,TERMINATED:已退出的线程处于这种状态。
二,Waiting(无线等待状态)
线程间通信概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。
如何保证线程间通信有效利用资源:
多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 就
是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效
的利用资源。而这种手段即—— 等待唤醒机制。
等待唤醒机制案例(线程之间的通信):
1,创建一个顾客线程(消费者):其中调用wait方法,放弃CPU的执行,进入到waiting状态(无限等待)。
2,创建一个老板线程(生产者):调用notify方法,唤醒消费者。
注意事项:
1,消费者及生产者线程必须都使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行;
2,同步使用的锁对象必须保证唯一;
3,只有锁对象才能调用wait和notify方法。
Object类中的方法:
void wait():在其他线程调用此对象的notify或者notifyAll方法之前,导致当前线程等待。
void notify():唤醒此对象监视器上等待的单线程,会继续执行wait方法之后的代码;若有多个线程会随机唤醒一个。
void notifyAll():唤醒对象监视器上的所有线程。
public class DemoWaitAndNotify {
public static void main(String[] args) {
Object obj = new Object();
new Thread(){
@Override
public void run() {
while (true){
synchronized (obj){
System.out.println("顾客1:告知老板需要包子的数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客1:开始吃包子");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客1:吃完包子了");
System.out.println("-------------------");
}
}
}
}.start();
Runnable rt = new Runnable(){
@Override
public void run() {
while (true){
synchronized (obj){
System.out.println("顾客2:告知老板需要包子的数量");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客2:开始吃包子");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客2:吃完包子了");
System.out.println("-------------------");
}
}
}
};
new Thread(rt).start();
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj){
System.out.println("老板:开始做包子...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老板:做好包子了");
// obj.notify();
/*
顾客1:告知老板需要包子的数量
顾客2:告知老板需要包子的数量
老板:开始做包子...
老板:做好包子了
顾客1:开始吃包子
顾客1:吃完包子了
-------------------
顾客1:告知老板需要包子的数量
老板:开始做包子...
老板:做好包子了
顾客2:开始吃包子
顾客2:吃完包子了
-------------------
*/
obj.notifyAll();
/*
顾客1:告知老板需要包子的数量
老板:开始做包子...
老板:做好包子了
顾客2:告知老板需要包子的数量
顾客1:开始吃包子
顾客1:吃完包子了
-------------------
顾客1:告知老板需要包子的数量
老板:开始做包子...
老板:做好包子了
顾客2:开始吃包子
顾客2:吃完包子了
-------------------
*/
}
}
}
}.start();
}
}
注意:哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以它需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。
三,消费者生产者模型
等待唤醒机制其实就是经典的“生产者与消费者”的问题。
共享资源:
public class BaoZi {
public String pi;
public String xian;
public Boolean state = false;
}
生产者:
public class DemoProduce extends Thread {
private BaoZi bz;
public DemoProduce(BaoZi bz) {
this.bz = bz;
}
@Override
public void run() {
int count = 0;
while (true){
synchronized (bz){
if (bz.state == false){
if (count%2 == 0){
bz.pi = "冰皮";
bz.xian = "韭菜";
}else{
bz.pi = "薄皮";
bz.xian = "牛肉";
}
bz.state = true;
count++;
}
System.out.println("老板:正在生产"+bz.pi+bz.xian+"陷包子");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老板:做好"+bz.pi+bz.xian+"陷包子");
bz.notify();
if (bz.state == true){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
消费者:
public class DemoConsume extends Thread {
private BaoZi bz;
public DemoConsume(BaoZi bz) {
this.bz = bz;
}
@Override
public void run() {
while (true){
synchronized (bz){
if (bz.state == false){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//被唤醒之后
System.out.println("顾客:开始吃"+bz.pi+bz.xian+"陷包子");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客:吃完"+bz.pi+bz.xian+"陷包子了");
bz.state = false;
System.out.println("-------------------");
bz.notify();
}
}
}
}
测试类:
public class DemoTest {
public static void main(String[] args) {
BaoZi bz = new BaoZi();
DemoConsume con = new DemoConsume(bz);
DemoProduce pro = new DemoProduce(bz);
con.start();
pro.start();
/*
老板:正在生产冰皮韭菜陷包子
老板:做好冰皮韭菜陷包子
顾客:开始吃冰皮韭菜陷包子
顾客:吃完冰皮韭菜陷包子了
-------------------
老板:正在生产薄皮牛肉陷包子
老板:做好薄皮牛肉陷包子
顾客:开始吃薄皮牛肉陷包子
顾客:吃完薄皮牛肉陷包子了
-------------------
老板:正在生产冰皮韭菜陷包子
老板:做好冰皮韭菜陷包子
顾客:开始吃冰皮韭菜陷包子
顾客:吃完冰皮韭菜陷包子了
-------------------
*/
}
}