线程状态
线程状态概述
线程分为6种状态,分别为:
- 新建状态,代表新建了一个线程
- 运行状态,代表正在运行
- 阻塞状态,表示线程没有执行
- 休眠状态:线程没有运行,到达时间或者或着执行notify()方法会被唤醒,当休眠时间结束,如果没有cpu执行权会进入阻塞状态
- 无限等待状态:当一个线程进入该状态,需要手动唤醒(noyity())
- 死亡状态:表示线程过时或结束。
具体关系如下图:
线程间的通信
多线程环境下CPU会随机的在线程之间进行切换,如果想让两个线程有规律的去执行,那就需要两个线程之间进行通信,在Object类中的两个方法wait和notify(或notifyAll)可以实现通信。
- wait方法可以使当前线程进入到等待状态,在没有被唤醒的情况下,线程会一直保持等待状态。
- notify方法可以随机唤醒单个在等待状态下的线程。
- notifyAll方法同时唤醒所有线程。
两个线程间的通信:
- 案例:交替打印99
public class Test99 {
//交替打印99
public static void main(String[] args) {
Object obj = new Object();
new Thread("t1"){
@Override
public void run() {
for (int i=0;i<10;i++){
synchronized (obj){
try {
System.out.println(this.getName()+"99");
obj.notify();
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}.start();
new Thread("t2"){
@Override
public void run() {
for (int i=0;i<10;i++) {
synchronized (obj){
try {
System.out.println(this.getName()+"99");
obj.notify();
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}.start();
}
}
结果显示:
案例:买卖包子
分析:消费者买包子,提供商生成包子。消费者去买包子,当没有包子,消费者等待,并通知提供商生产包子;提供商生产完成,等待包子被买,并通知消费者来买。
定义一个包子类,提供属性:
class BaoZi {
//皮
String pi;
//陷
String xian;
//包子的状态: 有 true,没有 false,设置初始值为false没有包子
boolean flag = false;
}
线程1,消费者:
/*
消费者(吃货)类:是一个线程类,可以继承Thread
设置线程任务(run):吃包子
对包子的状态进行判断
false:没有包子
吃货调用wait方法进入等待状态
true:有包子
吃货吃包子
吃货吃完包子
修改包子的状态为false没有
吃货唤醒包子铺线程,生产包子
*/
public class ChiHuo extends Thread{
//1.需要在成员位置创建一个包子变量
private BaoZi bz;
//2.使用带参数构造方法,为这个包子变量赋值
public ChiHuo(BaoZi bz) {
this.bz = bz;
}
//设置线程任务(run):吃包子
@Override
public void run() {
//使用死循环,让吃货一直吃包子
while (true){
//必须同时同步技术保证两个线程只能有一个在执行
synchronized (bz){
//对包子的状态进行判断
if(bz.flag==false){
//吃货调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//被唤醒之后执行的代码,吃包子
System.out.println("吃货正在吃:"+bz.pi+bz.xian+"的包子");
//吃货吃完包子
//修改包子的状态为false没有
bz.flag = false;
//吃货唤醒包子铺线程,生产包子
bz.notify();
System.out.println("吃货已经把:"+bz.pi+bz.xian+"的包子吃完了,包子铺开始生产包子");
System.out.println("----------------------------------------------------");
}
}
}
}
线程2:提供者
/*
生产者(包子铺)类:是一个线程类,可以继承Thread
设置线程任务(run):生产包子
对包子的状态进行判断
true:有包子
包子铺调用wait方法进入等待状态
false:没有包子
包子铺生产包子
增加一些趣味性:交替生产两种包子
有两种状态(i%2==0)
包子铺生产好了包子
修改包子的状态为true有
唤醒吃货线程,让吃货线程吃包子
注意:
包子铺线程和包子线程关系-->通信(互斥)
必须同时同步技术保证两个线程只能有一个在执行
锁对象必须保证唯一,可以使用包子对象作为锁对象
包子铺类和吃货的类就需要把包子对象作为参数传递进来
1.需要在成员位置创建一个包子变量
2.使用带参数构造方法,为这个包子变量赋值
*/
public class BaoZiPu extends Thread{
//1.需要在成员位置创建一个包子变量
private BaoZi bz;
//2.使用带参数构造方法,为这个包子变量赋值
public BaoZiPu(BaoZi bz) {
this.bz = bz;
}
//设置线程任务(run):生产包子
@Override
public void run() {
//定义一个变量
int count = 0;
//让包子铺一直生产包子
while(true){
//必须同时同步技术保证两个线程只能有一个在执行
synchronized (bz){
//对包子的状态进行判断
if(bz.flag==true){
//包子铺调用wait方法进入等待状态
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//被唤醒之后执行,包子铺生产包子
//增加一些趣味性:交替生产两种包子
if(count%2==0){
//生产 薄皮三鲜馅包子
bz.pi = "薄皮";
bz.xian = "三鲜馅";
}else{
//生产 冰皮 牛肉大葱陷
bz.pi = "冰皮";
bz.xian = "牛肉大葱陷";
}
count++;
System.out.println("包子铺正在生产:"+bz.pi+bz.xian+"包子");
//生产包子需要3秒钟
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//包子铺生产好了包子
//修改包子的状态为true有
bz.flag = true;
//唤醒吃货线程,让吃货线程吃包子
bz.notify();
System.out.println("包子铺已经生产好了:"+bz.pi+bz.xian+"包子,吃货可以开始吃了");
}
}
}
}
测试类:
/*
测试类:
包含main方法,程序执行的入口,启动程序
创建包子对象;
创建包子铺线程,开启,生产包子;
创建吃货线程,开启,吃包子;
*/
public class Demo {
public static void main(String[] args) {
//创建包子对象;
BaoZi bz =new BaoZi();
//创建包子铺线程,开启,生产包子;
new BaoZiPu(bz).start();
//创建吃货线程,开启,吃包子;
new ChiHuo(bz).start();
}
}
结果显示:
多线程通信:
与两个线程不同的是,需要使用notifyAll()同时唤醒多个线程
案例:三个线程同时打印99
public class ThreeThread {
private int flag = 1;
public void print1(){
synchronized(this){
while(flag != 1){
try {
//让当前线程进入等待状态
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程1打印99");
flag = 2;
//唤醒所有等待的线程
this.notifyAll();
}
}
public void print2(){
synchronized(this){
while(flag != 2){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程2打印99");
flag = 3;
this.notifyAll();
}
}
public void print3(){
synchronized(this){
while(flag != 3){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程3打印99");
System.out.println("-------------------------");
flag = 1;
this.notifyAll();
}
}
}
测试类:
public class ThreeTreadTest {
public static void main(String[] args) {
ThreeThread t = new ThreeThread();
Thread t1 = new Thread(){
@Override
public void run() {
for (int i = 0;i<10;i++){
t.print1();
}
}
};
Thread t2 = new Thread(){
@Override
public void run() {
for (int i = 0;i<10;i++){
t.print2();
}
}
};
Thread t3 = new Thread(){
@Override
public void run() {
for (int i = 0;i<10;i++){
t.print3();
}
}
};
t1.start();
t2.start();
t3.start();
}
}
结果: