线程的生命周期
在 Java 中线程从新建到关闭会经过不同的状态,将线程从新建到关闭作为一个生命周期,在 Java 中整个线程的生命周期有 6 种状态。
线程状态类型
在 JDK 的 Thread 类,存在 State
枚举类,包含了线程的 6 种状态。
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
NEW
新建 Thread,还没有开始执行。
RUNNABLE
可运行的 Thread,包含准备运行(运行但未分配到CPU)和正在运行的。
BLOCKED
线程被阻塞,等待资源锁的线程。
WAITING
正在无限期的等待其它线程执行。
TIMED_WAITING
在有限时间内等待其它线程执行。
TERMINATED
线程执行完毕。
/**
* 测试线程状态枚举
*/
@Test
public void testStateEmun() {
//线程状态枚举类
Thread.State[] values = Thread.State.values();
for (Thread.State value : values) {
String name = value.name();
System.out.println(name);
}
}
线程状态切换
在一定程度上是不可逆转的,比如线程执行之后不会回到 NEW
状态,线程关闭之后(TERMINATED)也不会回到 RUNNABLE
状态。
1. NEW
线程类 Thread 在创建之后的状态为 NEW
。
/**
* 测试NEW
*/
@Test
public void testNewState() {
Thread thread = new Thread(() -> {
});
//未运行的线程状态是NEW
Thread.State state = thread.getState();
System.out.println(state.name());
}
2. RUNNABLE
在线程处于新建就绪状态(NEW),调用 start()
方法开始执行,进入运行状态(RUNNABLE)。
注意此过程不可逆,线程进入运行状态(RUNNABLE)后,无法回到新建状态(NEW)。
@Test
public void testRunnableState() {
Thread thread = new Thread(() -> {
});
//调用run方法,并不会启动线程,此时运行状态还是NEW
// thread.run();
//线程启动后,运行状态为RUNNABLE
thread.start();
Thread.State state = thread.getState();
System.out.println(state.name());
}
3. BLOCKED
线程在遇到需要临界资源的时候,若没有竞争到临界资源,线程就从运行状态(RUNNABLE)进入到阻塞状态(BLOCKED),当线程竞争到临界资源之后会从阻塞状态回归到运行状态。
/**
* 测试BLOCKED
*/
@Test
public void testBlockedState() {
Object object = new Object();
Runnable runnable = () -> {
synchronized (object) {
while (true) {
//线程独占资源,谁先抢到谁运行,未抢到的会阻塞
}
}
};
Thread threadOne = new Thread(runnable);
Thread threadTwo = new Thread(runnable);
//线程one获取资源,状态为:RUNNABLE
threadOne.start();
//线程two被阻塞,状态为:BLOCKED
threadTwo.start();
System.out.println("threadOne name :" + threadOne.getName() + "; state :" + threadOne.getState().name());
System.out.println("threadTwo name :" + threadTwo.getName() + "; state :" + threadTwo.getState().name());
}
4. WAITING
有三种方法可以使线程从运行状态(RUNNABLE)到等待状态(WAITING)。
object.wait()
thread.join()
LockSupport.park()
对应的 WAITING -> RUNNABLE 状态,有以下几种方式。
notify()
notifyAll()
LockSupport.unpark()
/**
* 测试WAITING
* 使用object.wait()
*/
@SneakyThrows
@Test
public void testWaitingState() {
//对象锁
Object object = new Object();
//第一个线程等待
Thread threadOne = new Thread(() -> {
try {
Thread.sleep(1000);
synchronized (object) {
System.out.println("threadOne wait!!!");
//threadOne进行等待
object.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("threadOne被唤醒之后继续执行!");
System.out.println("threadOne end!");
});
//第二个线程通知
Thread threadTwo = new Thread(() -> {
try {
Thread.sleep(3000);
System.out.println("threadOne state:" + threadOne.getState().name());
synchronized (object) {
System.out.println("threadTwo notify threadOne!!!");
//唤醒threadOne(并不直接释放锁,而是让threadOne开始竞争锁)
object.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("threadTwo notify threadOne 后并没有直接退出,而是继续执行!!!");
});
threadOne.start();
threadTwo.start();
Thread.sleep(10000);
}
/**
* 测试WAITING
* 使用thread.join()
*/
@SneakyThrows
@Test
public void testWaitingStateJoin() {
//第一个线程睡眠
Thread threadOne = new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//第二个线程等待第一个线程
Thread threadTwo = new Thread(() -> {
try {
//等待ThreadOne执行完毕
threadOne.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadOne.start();
threadTwo.start();
Thread.sleep(1000);
System.out.println("threadTwo state:"+threadTwo.getState().name());
Thread.sleep(10000);
}
/**
* 测试WAITING
* 使用LockSupport.park()
*/
@SneakyThrows
@Test
public void testWaitingStateLockSupport() {
//第一个线程阻塞
Thread threadOne = new Thread(() -> {
//开始阻塞
LockSupport.park();
System.out.println("threadOne unpark!!!");
while (true){}
});
//第二个线程等待第一个线程
Thread threadTwo = new Thread(() -> {
try {
Thread.sleep(3000);
//取消阻塞(RUNNABLE->WAITING)
LockSupport.unpark(threadOne);
Thread.sleep(1000);
System.out.println("threadOne unpark state:"+threadOne.getState().name());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
threadOne.start();
threadTwo.start();
Thread.sleep(1000);
System.out.println("threadOne state:"+threadOne.getState().name());
Thread.sleep(10000);
}
5. TIME_WAITING
有多种方式可以使线程从运行状态(RUNNABLE)到有限等待状态(TIME_WAITING)。
thread.sleep(long millis)
wait(int timeout)
thread.join(long millis)
LockSupport.parkNanos(long nanos)
LockSupport.parkUntil()
对应的 TIME_WAITING -> RUNNABLE 状态,有以下几种方式。
- 自然到期。
notify()
notifyAll()
LockSupport.unpark()
/**
* 测试TIME_WAITING
*/
@SneakyThrows
@Test
public void testTimeWaitintState() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
Thread.sleep(1000);
//TIMED_WAITING
System.out.println("thread state:" + thread.getState().name());
Thread.sleep(10000);
}
6. TERMINATED
线程在执行完成之后会从运行状态(RUNNABLE)进入到关闭状态(TERMINATED)。
注意此过程不可逆,线程关闭之后(TERMINATED)不会回到 RUNNABLE
状态。
/**
* 测试TERMINATED
*/
@SneakyThrows
@Test
public void testTerminatedState() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
Thread.sleep(1000);
System.out.println(thread.getState().name());
}