线程状态
线程的状态 在Thread中有一个枚举类进行标识
/**
* 线程状态
*
* NEW 尚未启动的线程处于这种状态
* RUNNABLE 在 JVM 上执行的线程处于这种状态
* BLOCKED 被阻止等待监视器锁的线程处于这种状态
* WAITING 即无限期地等待另一个线程来执行某一特定操作的线程处于这种状态
* TIMED_WAITING 正在等待另一个线程来达到一个指定的等待时间执行动作的线程处于这种状态
* TERMINATED 已退出的线程处于这种状态
* 一个线程可以在给定时间点只能处于一种状态。这些状态是 JVM 的状态并没有反映任何操作系统线程状态
*
* @see #getState
*/
public enum State {
/**
* 线程还没有启动
*/
NEW,
/**
* 运行中的线程
*/
RUNNABLE,
/**
* 阻塞的,可能是在等待进入同步块/方法时被阻塞的
* WAITING 不同在于, BLOCKED 是还没有进入同步块/方法时被阻塞,WAITING 是已经进去到获取同步块的过程中了,但却获取不到锁
*/
BLOCKED,
/**
* 等待,遇到 Object#wait()、Thread.join、LockSupport#park() 这些方法时,线程就会等待
* 等待另外一个线程执行特定的操作
* 一个线程 Object.wait() 后,需要等待另外一个线程执行同一个 Object 的 notify()
* 或者线程执行 thread1.join(),等待 thread1 来打断
*/
WAITING,
/**
* 等待一定的时间
*/
TIMED_WAITING,
/**
* 终止线程
*/
TERMINATED;
}
总体上来说其实就是 新建、可运行、无限等待、有限等待、阻塞、结束。
重点掌握的其实就是无限等待、有限等待、阻塞这三种。
演示
NEW
public static class ThreadTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行前");
System.out.println(Thread.currentThread().getName() + " 执行后");
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new ThreadTask());
TimeUnit.SECONDS.sleep(1);
System.out.println(t1.getName() + " stateName :" + t1.getState());
}
Thread-0 stateName :NEW
RUNNABLE
t1.start(); // 获取线程状态就是运行态
Thread-0 stateName :RUNNABLE
TERMINATED
线程执行完毕,之后就会终止
Thread-0 stateName :TERMINATED
BLOCKED
BLOCKED阻塞状态 其实就是在syn修饰的方法、代码块中 同一时刻没有获取到锁,进入BLOCKED阻塞状态。
private Object o = new Object();
public static class ThreadTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行前");
try {
doExec();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行后");
}
synchronized void doExec() throws InterruptedException {
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName() + " 执行中");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTask threadTask = new ThreadTask();
Thread t1 = new Thread(threadTask);
t1.start();
TimeUnit.SECONDS.sleep(1);
Thread t2 = new Thread(threadTask);
t2.start();
System.out.println(t1.getName() + " stateName :" + t1.getState());
System.out.println(t2.getName() + " stateName :" + t2.getState());
}
Thread-0 stateName :TIMED_WAITING
Thread-1 stateName :BLOCKED
WAITING
wait
获得syn隐士锁的时候,调用了无参的wait() 方法,线程进入wait() . 需要调用notify/ nofityAll()进行唤醒。
private Object o = new Object();
public static class ThreadTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行前");
try {
doExec();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行后");
}
synchronized void doExec() throws InterruptedException {
wait();
System.out.println(Thread.currentThread().getName() + " 执行中");
}
synchronized void doNotify() throws InterruptedException {
notify();
System.out.println(Thread.currentThread().getName() + " 执行中");
}
synchronized void donotifyAll() throws InterruptedException {
notifyAll();
System.out.println(Thread.currentThread().getName() + " 执行中");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTask threadTask = new ThreadTask();
Thread t1 = new Thread(threadTask);
t1.start();
TimeUnit.SECONDS.sleep(1);
System.out.println(t1.getName() + " stateName :" + t1.getState());
// threadTask.doNotify();
threadTask.donotifyAll();
System.out.println(t1.getName() + " stateName :" + t1.getState());
}
Thread-0 stateName :WAITING
join
park()
调用 LockSupport.park() 方法,当前线程会阻塞,线程的状态会从 RUNNABLE 转换到 WAITING。调用 LockSupport.unpark(Thread thread) 可唤醒目标线程,目标线程的状态又会从 WAITING 状态转换到 RUNNABLE。
public static class ThreadTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行前");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + " 执行后");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTask threadTask = new ThreadTask();
Thread t1 = new Thread(threadTask);
t1.start();
TimeUnit.SECONDS.sleep(3);
System.out.println(t1.getName() + " stateName :" + t1.getState());
LockSupport.unpark(t1);
TimeUnit.SECONDS.sleep(3);
System.out.println(t1.getName() + " stateName :" + t1.getState());
}
Thread-0 执行前
Thread-0 stateName :WAITING
Thread-0 执行后
Thread-0 stateName :TERMINATED
TIMED_WAITING
超时的sleep
public static class ThreadTask implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行前");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 执行后");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTask threadTask = new ThreadTask();
Thread t1 = new Thread(threadTask);
t1.start();
TimeUnit.SECONDS.sleep(3);
System.out.println(t1.getName() + " stateName :" + t1.getState());
}
Thread-0 执行前
Thread-0 stateName :TIMED_WAITING
Thread-0 执行后
面试问题
一个线程两次调用 start() 方法会出现什么情况?
抛出异常,IllegalMonitorStateException 不可以被start() 两次
if (threadStatus != 0)
throw new IllegalThreadStateException();
BLOCKED与WAITING的区别
blocked其实是线程在等待获取锁 获取失败后,被动触发的状态,会在此尝试获取锁,会自动唤醒。
WAITING是属于人为的主动触发的行为,线程等待其他线程发来的通知(notify\ notifyAll \ unpark()) 收到通知后,可能会顺序向后执行(RUNNABLE),也可能会再次获取锁,进而被阻塞住(BLOCKED)。