线程状态(计时等待,锁阻塞,无限等待(重点))

一:线程状态

1.线程状态概述(有6中线程状态)
①:new(新建)–线程刚被创建,但是并未启动。还没调用start方法。
②:Runnable(可运行) --线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
③:Blocked(锁阻塞)–当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
④:Waiting(无限等待)–一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
⑤:Timed Waiting(计时等待)–同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。
⑥:Teminated(被终止)–因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

图的展示
在这里插入图片描述

2.计时等待
例子:
// 演示线程的休眠状态
class ThreadSleep implements Runnable {
// 创建线程任务,模拟闹钟
public void run() {
// 10秒钟闹钟自动报警
for( int i = 1; i <= 10; i++ ) {
// 模拟输出秒
System.out.println(“第”+ i +“秒!”);
// 让线程休息1000毫秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(“叮铃铃…”);
}
}
public class ThreadSleepDemo {
public static void main(String[] args) {
// 创建线程任务
ThreadSleep ts = new ThreadSleep();
// 创建线程对象
Thread t = new Thread( ts );
// 启动线程任务
t.start();
}
}

3.锁阻塞
线程A与线程B代码中使用同一锁,如果线程A获取到锁,线程A进入到Runnable状态,那么线程B就进入到Blocked锁阻塞状态。
简单来说,就是启动之后没有获取到锁的线程。处于此状态。

4.无限等待

4.1.生产者和消费者

①:生产者和消费者(应用场景)–多个线程在处理同一个共享资源容器,但是处理的方式(线程的任务)却不相同。
②:例子:线程A用来生成包子放到资源容器中,线程B是从容器中拿包子吃,存放包子的容器可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题。
③:共享的资源容器:
// 资源容器类
public class BaoZiPu {
/*
定义数组,充当保存包子的容器.
如果数组中保存的数据为null,说明容器中没有包子
如果数组中保存的数据非null,说明容器中有包子
/
private String[] str = new String[1];
// 定义变量,记录包子的生产个数
private int count = 1;
// 定义锁对象
private Object lock = new Object();
/

基于容器的操作有两种:
一种是给容器中保存数据
一种是从容器中取出数据
*/
// 给容器中保存包子的方法
public void add( String name ) {
synchronized ( lock ) {
try {Thread.sleep(10);}catch(InterruptedException e) {}
// 保存包子
str[0] = name + count;
System.out.println(“生产者给容器中保存…” + str[0]);
// 保存完成后,记录包子个数的变量+1
count++;
}
}
// 从容器中取出包子的方法
public void get(){
synchronized ( lock ) {
try {Thread.sleep(10);}catch(InterruptedException e) {}
// 打印模拟包子取出
System.out.println(“消费者从容器中取出…” + str[0]);
// 包子取出后,将容器空间置位null
str[0] = null;
}
}
}

生产者类:
// 生成者线程
public class Producer implements Runnable {
// 定义资源容器对象
private BaoZiPu bzp;
// 构造方法,在创建对象时,给资源容器对象赋值
public Producer( BaoZiPu bzp ) {
this.bzp = bzp;
}

// 线程任务是给容器中保存包子
public void run() {
    // 调用保存的方法
    while( true ) {
        bzp.add("肥肉馅大包子...");
    }
}

}

消费者类:
// 消费者线程
public class Consumer implements Runnable{
// 定义资源容器对象
private BaoZiPu bzp;
// 构造方法,在创建对象时,给资源容器对象赋值
public Consumer(BaoZiPu bzp) {
this.bzp = bzp;
}

// 线程任务是从容器中取出包子
public void run() {
    while( true ) {
        bzp.get();
    }
}

}

测试类:
public class ProducerConsumerDemo {
public static void main(String[] args) {
// 创建共享资源包子铺对象
BaoZiPu bzp = new BaoZiPu();
// 创建生产者线程任务对象
Producer pro = new Producer( bzp );
// 创建消费者线程任务对象
Consumer con = new Consumer( bzp );

    // 创建生产者线程对象
    Thread pro_thread = new Thread( pro );
    // 创建消费者线程对象
    Thread con_thread = new Thread( con );
    // 启动生产者和消费者线程任务
    pro_thread.start();
    con_thread.start();
}

}

4.2.线程通信(而要实现线程间的通信,就需要使用等待唤醒机制。)

  • void wait() 导致当前线程等待,直到其他线程调用notify()或notifyAll()方法将其唤醒。

    • 线程调用wait()方法,将释放它对锁的拥有权,然后等待另外的线程来唤醒它,这样它才能重新获得锁的拥有权和恢复执行。
  • void notify() 唤醒正在等待对象监视器的(任意)单个线程。 唤醒的线程是随机性的。

  • void notifyAll() 唤醒正在等待对象监视器的所有线程。

4.3.等待唤醒机制

// 资源容器类
/*
添加等待唤醒机制,解决大量保存和取出的问题
/
public class BaoZiPu {
/

定义数组,充当保存包子的容器.
如果数组中保存的数据为null,说明容器中没有包子
如果数组中保存的数据非null,说明容器中有包子
*/

private String[] str = new String[1];

// 定义变量,记录包子的生产个数
private int count = 1;

// 定义锁对象
private Object lock = new Object();
/*
    基于容器的操作有两种:
        一种是给容器中保存数据
        一种是从容器中取出数据
 */
// 给容器中保存包子的方法
public void add( String name ) {
    synchronized ( lock ) {
        // 给容器中保存包子前,先判断容器中是否存在包子
        if( str[0] != null ) {
            // 容器中有包子存在,则调用wait方法让生产者等待
            try {lock.wait();} catch (InterruptedException e) {}
        }

        try {Thread.sleep(10);} catch (InterruptedException e) {}
        // 保存包子
        str[0] = name + count;
        System.out.println("生产者给容器中保存..." + str[0]);
        // 保存完成后,记录包子个数的变量+1
        count++;

        // 代码执行到此处,说明商品已经保存完成,唤醒消费者消费商品
        lock.notify();
    }
}
// 从容器中取出包子的方法
public void get(){
    synchronized ( lock ) {
        // 从容器中取出包子前,先判断容器中是否存在包子
        if( str[0] == null ) {
            // 容器中没有包子存在,则调用wait方法让消费者等待
            try {lock.wait();} catch (InterruptedException e) {}
        }
        try {Thread.sleep(10);} catch (InterruptedException e) {}
        // 打印模拟包子取出
        System.out.println("消费者从容器中取出....." + str[0]);
        // 包子取出后,将容器空间置位null
        str[0] = null;

        // 代码执行到此处,说明商品已经消费完成,唤醒生成者生成商品
        lock.notify();
    }
}

}

猜你喜欢

转载自blog.csdn.net/ZY__99/article/details/107458247