线程(三)

本文详细介绍了Java线程的五种状态,包括新建、可运行、阻塞、无限等待和计时等待。重点讨论了TimedWaiting(sleep())和Waiting(wait())状态,通过实例解析它们的使用场景和区别。sleep()方法会让线程在指定时间后自动苏醒,而wait()则需要其他线程调用notify()或notifyAll()来唤醒。此外,wait()会释放锁,而sleep()则不会。
摘要由CSDN通过智能技术生成

线程状态

1 线程状态概述

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是⼀直处于执⾏状态。在线
程的⽣命周期中,有⼏种状态呢?在 API 中 java.lang.Thread.State 这个枚举中给出了六种线程状态:

线程状态导致状态发生的条件
new (新建)线程刚被创建,但是并未启动。还没调用start方法
Runable(可运行)线程可以在java 虚拟机中运行的状态,可能正在运行自己的代码,也可能没有。这个取决于操作系统处理器
Blocked(锁阻塞)当一个线程试图获取一个对象锁,而该对象被其他的线程持有,则给线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态
Waiting(⽆限等待)⼀个线程在等待另⼀个线程执⾏⼀个(唤醒)动作时,该线程进⼊Waiting状态。进⼊这个状态后是不能⾃动唤醒的,必须等待另⼀个线程调⽤notify或者notifyAll⽅法才能够唤醒。
Timed Waiting(计时等待)同waiting状态,有⼏个⽅法有超时参数,调⽤他们将进⼊TimedWaiting状态。这⼀状态将⼀保持到超时期满或者接收到唤醒通知。带有超时参数的常⽤⽅法有Thread.sleep、Object.wait
Teminated(被终⽌)因为run⽅法正常退出⽽死亡,或者因为没有捕获的异常终⽌了run⽅法⽽死亡。

在这里插入图片描述

2 Timed Waiting(计时等待)

在卖票的案例中,为了减少线程执行太快,现象不明显等问题,我们在run方法中添加了sleep语句,这样就强制当前正字执行的线程休眠(暂停执行),以“减缓线程”。
调用sleep方法之后,当前执行的线程就会进入到“休眠状态”,其实就是所谓的Timed Waiting(计时等待),那么通过一个案例加深对该状态的理解。
实现一个计数器,计数到100,在每个数字机之间暂停1秒,每隔10个数字输出一个字符串。

public class MyThread extends Thread {
 public void run() {
 for (int i = 0; i < 100; i++) {
 if ((i) % 10 == 0) {
 System.out.println("-------" + i);
 }
 System.out.print(i);
 try {
 Thread.sleep(1000);
 System.out.print(" 线程睡眠1秒!\n");
 } catch (InterruptedException e) {
 e.printStackTrace(); }
 }
 }
 public static void main(String[] args) {
 new MyThread().start();
 }
}
  1. 进⼊ TIMED_WAITING 状态的⼀种常⻅情形是调⽤的 sleep ⽅法,单独的线程也可以调⽤,
    不⼀定⾮要有协作关系。
  2. 为了让其他线程有机会执⾏,可以将Thread.sleep()的调⽤放线程run()之内。这样才能保证
    该线程执⾏过程中会睡眠。
  3. sleep与锁⽆关,线程睡眠到期⾃动苏醒,并返回到Runnable(可运⾏)状态

sleep()中指定的时间是线程不会运⾏的最短时间。因此,sleep()⽅法不能保证该线程睡眠到期后就开始⽴刻执⾏。

Timed Waiting 线程状态图:
在这里插入图片描述

3 BLOCKED(锁阻塞)

Blocked 状态在 API 中的介绍为:⼀个正在阻塞等待⼀个监视器锁(锁对象)的线程处于这⼀状态
⽐如,线程A与线程B代码中使⽤同⼀锁,如果线程A获取到锁,线程A进⼊到 Runnable 状态,那么线程B就进⼊到 Blocked 锁阻塞状态。
这是由 Runnable 状态进⼊ Blocked 状态。除此 Waiting 以及 Time Waiting 状态也会在某种情
况下进⼊阻塞状态。
Blocked 线程状态图:
在这里插入图片描述

4 Waiting(⽆限等待)

Wating 状态在 API 中介绍为:⼀个正在⽆限期等待(waiting)另⼀个线程执⾏⼀个特别的notify()/notifyAll()(唤醒)动作的线程处于这⼀状态。

public class WaitingTest {
 public static Object obj = new Object();
 
 public static void main(String[] args) {
 // 演示waiting
 new Thread(new Runnable() {
 @Override
 public void run() {
 while (true) {
 synchronized (obj) {
 try {
 System.out.println(Thread.currentThread().getName() + "=== 获
取到锁对象,调⽤wait⽅法,进⼊waiting状态,释放锁对象");
 obj.wait(); // ⽆限等待
 // obj.wait(5000); // 计时等待, 5秒 时间到,⾃动醒来
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println(Thread.currentThread().getName() 
 + "=== 从waiting状态醒来,获取到锁对象,继续执⾏了");
 }
  }
 }
 }, "等待线程").start();
 
 new Thread(new Runnable() {
 @Override
 public void run() {
// while (true) { // 每隔3秒 唤醒⼀次
 try {
 System.out.println(Thread.currentThread().getName() + "----- 等 待3秒钟");
 Thread.sleep(3000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 synchronized (obj) {
 System.out.println(Thread.currentThread().getName() + "----- 获
取到锁对象,调⽤notify⽅法,释放锁对象");
 obj.notify();
 }
 }
// }
 }, "唤醒线程").start();
 }
}

1.通过上述案例发现:一个调用了某个对象的Object.wait()方法的线程会等待另一个线程调用此对象的Object.notify方法或者Object.notifyAll()方法。
2.其实 waiting 状态并不是⼀个线程的操作,它体现的是多个线程间的通信,可以理解为多个线程
之间的协作关系,多个线程会争取锁,同时相互之间⼜存在协作关系。
3.当多个线程协作时,⽐如A,B线程,如果A线程在 Runnable(可运⾏)状态中调⽤了 wait() ⽅
法那么A线程就进⼊了Waiting(⽆限等待)状态,同时失去了同步锁。假如这个时候B线程获取
到了同步锁,在运⾏状态中调⽤了 notify() ⽅法,那么就会将⽆限等待的A线程唤醒。注意是唤
醒,如果获取到锁对象,那么A线程唤醒后就进⼊ Runnable(可运⾏)状态;如果没有获取锁对
象,那么就进⼊到 Blocked(锁阻塞状态)
Waiting 线程状态图:
在这里插入图片描述

5 sleep()方法和wait()方法的区别和共同点

1.两者最主要的区别在于:sleep() 方法没有释放锁,而 wait() 方法释放了锁
2.两者都可以暂停线程的执行。
3.wait() 通常被用于线程间交互/通信,sleep() 通常被用于暂停执行。
4.wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法。
sleep() 方法执行完成后,线程会自动苏醒。或者可以使用 wait(long timeout) 超时后线程会自动苏醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值