一:线程状态
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();
}
}
}