1 线程的状态
public class ThreadState {
public static void main(String[] args) {
for (Thread.State state : Thread.State.values()) {
System.out.println(state);
}
}
}
-
新建(New):
意义:线程刚刚被创建但尚未开始执行。在这个状态下,线程对象已经被创建,但还没有调用其start()
方法来启动线程执行。线程此时不会占用系统资源,只是处于等待被启动的状态。 -
就绪(Runnable):
意义:线程是可工作的。又可以分成正在工作中和即将开始工作,但是没有明确的区分,两种情况下都称之为Runnable。 -
阻塞(Blocked):
意义:线程被阻塞,暂时无法继续执行。这可能是因为线程在等待某个资源(如锁、IO操作、等待其他线程的通知等)而被挂起,无法继续执行任务。 -
等待(Waiting):
意义:线程进入等待状态,等待特定条件的满足。线程会等待,直到其他线程显式地唤醒它或者等待的条件变为真。 -
超时等待(Timed Waiting):
意义:线程进入有限时间的等待状态。与等待状态类似,但可以设置一个超时时间,线程会等待一段时间后自动唤醒。
2 状态转换
2.1NEW 、 RUNNABLE 、TERMINATED 状态的转换
public class ThreadStateTransfer {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 100; i++) {
}
}, "thread-1");
System.out.println(t.getName() + ": " + t.getState());;
t.start();
while (t.isAlive()) {
System.out.println(t.getName() + ": " + t.getState());;
}
System.out.println(t.getName() + ": " + t.getState());;
}
}
从代码中我们可以清楚的看到线程thread-1从创建到执行完毕自己的“任务”的整个状态转换,NEW-RUNNABLE-TERMINATED。
2.2 WAITING 、 BLOCKED 、 TIMED_WAITING 状态
首先看一下TIME_WAITING和BOLCKED状态,通过代码的方式来认识一下这两个状态的含义。
public class ThreadStateTransfer2 {
public static void main(String[] args) {
final Object object = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "t1");
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("hehe");
}
}
}, "t2");
t2.start();
}
}
在这个代码中线程t1首先获取到锁,然后自己会一直进入休眠(休眠是带有时间上限的,但是又与while的条件实际上是无休止的休眠,单独对于一次休眠等待来说是有时间上限的。)线程t2此时创建并启动但是由于获取不到锁对象,因此进入阻塞状态等待线程t1释放锁对象。
使用jconsole工具来查看当前两个线程的状态:
那么WAITING状态又是怎么样子的呢?
只需要将上面代码中的t1中的sleep换成wait即可:
public class ThreadStateTransfer2 {
public static void main(String[] args) {
final Object object = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
try {
//修改这个sleep
//Thread.sleep(1000);
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t1");
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("hehe");
}
}
}, "t2");
t2.start();
}
}
此时线程t1同样是率先获得锁对象,但是不在进行“休眠操作”,而是直接进入等待状态同时放开自己拥有的锁对象,此时的等待是等待拥有此锁对象的其他线程来通知t1结束等待,可惜的是t1永远也等待不到通知(代码中没有写....)。然后t1再启动,这次t1不再进入阻塞状态,因为此时的锁对象被t1所获取到后又通过wait释放了。
通过jconsole来观察此时的t1的状态(waiting):
而此时t2由于获取到锁对象,进入正常的工作,t2的状态就是RUNNABLE然后会转换成TERMINATED.
那么t1如何从WAITING装换成RUNNABLE呢?只需要线程t2在结束自己的任务后,使用notify来通知t1线程即可。(就是谢谢你t1刚才等待我,让出锁,现在我t2事务工作执行完成了,你t1可以继续执行了)
public class ThreadStateTransfer2 {
public static void main(String[] args) {
final Object object = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
try {
//修改这个sleep
//Thread.sleep(1000);
System.out.println("t1 wait 之前");
object.wait();
System.out.println("t1 收到了通知");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t1");
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("t2 工作打印,hehe");
object.notify();
}
}
}, "t2");
t2.start();
System.out.println("t1 的状态:"+t1.getState());
System.out.println("t2 的状态:"+t2.getState());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 的状态:"+t2.getState());
}
}
可以看到t1的状态从WAITING到最终TERMINATED的一个变化。
2.3 yield()----大公无私,让出cpu
public class ThreadYield {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("张三");
// 先注释掉, 再放开
// Thread.yield();
}
}
}, "t1");
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("李四");
}
}
}, "t2");
t2.start();
}
}
运行以上代码,可以观察到打印出张三、李四的数量大概是五五开,两者同时抢占式执行。
但是使用了yield()之后张三的数量就会远远小于李四,也就是线程t1在yield之后会让出cpu,此时不改变线程的状态,t1的状态一直都是RUNNABLE但是t1回去就绪队列中重新排队。之前说的RUNNABLE包含两种情况,一种是就绪中(可以工作)只是在排队,还有一种就是在执行中。