活动地址:CSDN21天学习挑战赛
目录
一、线程状态(Thread.state)概述
1.1 六种线程状态
线程状态 | 发生条件 |
NEW创建状态 | 线程刚被创建,但是并未调用start方法启动。 |
Runnable可运行状态 | 调用start方法后,线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready); 就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 |
Blocked阻塞状态 | 线程阻塞于锁。 |
Timed Waiting计时等待 | 调用带有超时参数的方法(常见的有Thread.sleep 、Object.wait)进入等待,当超过时间时被自动唤醒。 |
Waiting无限等待 | 等待另一个线程执行动作,进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。 |
Teminated终止状态 | 因为run方法正常退出或者因为没有捕获的异常终止了run方法而死亡。 |
1.2 线程状态关系图
线程的创建及终止比较容易理解,下面主要阐述线程从Runnable(可运行)状态与非运行状态之间的转换问题 ,即Timed Waiting计时等待、Waiting无限等待两种状态。
二、Timed Waiting (计时等待)
“计时等待”作用:
在run方法中添加了sleep( 数值)语句,相当于强制当前正在执行的线程休眠(暂停执行),以“减慢线程”,可以解决线程执行太快,现象不明显等问题。
举例1:设计一个计数器,计数到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)将Thread.sleep()的调用放线程run()之内,使得该线程执行过程中会暂停;
2)sleep与锁无关,线程睡眠到规定时间后自动被唤醒,并返回到Runnable(可运行)状态;
3)sleep()中指定的时间是线程不会运行的最短时间,即sleep()方法不能保证该线程睡眠到期后就开始立刻执行。
三、Waiting (无限等待)
waiting等待体现的是多个线程间的通信:多个线程会争取锁,同时相互之间又存在协作关系 。
当多个线程协作时,如A,B两个线程,如果A线程在Runnable(可运行)状态中调用了wait()方法那么A线程就进入了Waiting(无限等待)状态,同时失去了同步锁。假如这个时候B线程获取到了同步锁,在运行状态中调用了notify()方法,那么就会将无限等待的A线程唤醒。注意是唤醒,如果获取到锁对象,那么A线程唤醒后就进入Runnable(可运行)状态;如果没有获取锁对象,那么就进入到Blocked(锁阻塞状态)。
举例2:A线程调用wait()方法后,观察A,B两个线程的运行顺序
package Thread;
public class WaitingTest{
public static Object obj = new Object();
public static void main(String[] args) {
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);//计时等待5s,时间到后自动被唤醒
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "===从waiting状态醒来,获取到锁对象,继续执行");
}
}
}
},"A等待线程").start();
new Thread(new Runnable() {
@Override
public void run() {
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();
}
}
},"B唤醒线程").start();
}
}
四、线程等待的wait和sleep操作
线程等待的方法有三种:①Thread.sleep(long millis);②Object.wait(long timeout);③wait();【也称为“唤醒wait”】
其中,②、③的wait方法必须在同步块中使用,即
synchronized (obj) {
......
obj.wait();
......
}
Java中wait和sleep的区别,参考博文:java中wait和sleep的区别