Java线程的状态与主要转换方法

[TOC]

操作系统中的线程状态转换

在现代操作系统中,线程被视为轻量级进程,所以操作系统中线程的状态其实是和操作系统中进程的状态是一致的。

操作系统中线程状态转换.png

操作系统中线程主要有三个状态:

  • 就绪状态(ready):线程正在等待使用CPU,等分配到CPU时间片就可以进入running状态。
  • 执行状态(running):线程正在使用CPU。
  • 等待状态(waiting):线程经过等待事件的调用或者正在等待其他资源,如 I/O等。

Java线程的6个状态

Java中有一个枚举类,代表了Java线程的6个状态,其源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}

NEW

处于NEW状态的线程尚未启动,即未调用Thread类的start方法。

start方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);

boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}

可以看到,start()方法的内部有一个threadStatus变量,如果它不为0,会直接抛出异常。

在第一次调用start()方法后,threadStatus变量会从0变为其他值,若第二次调用start()方法就会抛出IllegalThreadStateException异常。

RUNNABLE

RUNNABLE表示当前线程正在运行中。RUNNABLE状态的线程运行在虚拟机中,也有可能在等待操作系统的其他资源。Java中RUNNABLE状态其实包括了操作系统线程的readywaiting两个状态。

BLOCKED

阻塞状态。处于BLOCKED状态的线程正等待锁的释放以进入同步区。

WAITING

等待状态。处于等待状态的线程要想变为RUNNABLE状态需要其他线程唤醒。

调用下面三个方法会使线程进入WAITING状态:

  • Object wait():使当前线程处于等待状态直到另一个线程唤醒它。
  • Thread.join():等待线程执行完毕,底层调用的是Object实例的wait方法。
  • LockSupport.park():除非获得调用许可,否则禁止当前线程进行线程调度。

TIMED_WAITING

超时等待状态。线程等待一个具体的时间,时间到后自动唤醒。

调用下面方法会使线程进入超时等待状态:

  • Tread.sleep(long millis):使当前线程睡眠指定时间
  • Object wait(long millis):线程休眠指定时间,等待期间可以通过notify()方法唤醒。
  • Thread.join(long millis):等待当前线程最多执行millis毫秒,如果millis为0,则会一直执行。
  • LockSupport.parkNanos(long nanos):除非获得调用许可,否则禁用当前线程进行线程调度指定时间。
  • LockSupport.parkUntil(long deadline):同上,也是禁止线程进行调度指定时间。

TERMINATED

终止状态,线程执行完毕。

线程状态的转换

线程状态的转换

BLOCKEDRUNNABLE状态的转换

处于BLOCKED状态的线程是因为在等待锁的释放。当线程获取到锁之后就会进入RUNNABLE状态。

WAITING状态与RUNNABLE状态的转换

将线程从RUNNABLE状态转换为WAITING状态主要有2种方法。

  • Object.wait()

    调用wait()方法前线程必须持有对象的锁,调用wait()方法后,会释放当前的锁,直到其他线程调用notify()notifyAll()唤醒等待锁的线程

  • Thread.join()

    调用join()方法不会释放锁,会一直等待当前线程执行完毕(转换为TERMINTED状态)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
    Thread a = new Thread(() -> {
    new ThreadTest().testMethod();
    });
    Thread b = new Thread(() -> {
    new ThreadTest().testMethod();
    });
    a.start();
    a.join();
    b.start();
    System.out.println(a.getName() + ": " + a.getState());
    System.out.println(b.getName() + ": " + b.getState());
    }

    private synchronized void testMethod() {
    try {
    Thread.sleep(2000l);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }


    //输出结果为
    Thread-0: TERMINATED
    Thread-1: TIMED_WAITING

    要是没有调用join()方法,main线程不管a线程是否执行完毕都会往下执行,但a线程启动后立刻调用了join()方法,这里main线程就会等待直到a执行完毕(转换为TERMINTED状态)。

    所以a会打印的状态为TERMINATED,而b线程可能为TIMED_WAITING状态(已进入同步方法)也可能为RUNNABLE状态(未进入同步方法)。

TIMED_WAITINGRUNNABLE状态的转换

TIMED_WAITINGWAITING状态类似,只是TIMED_WAITING等待时间是指定的。

  • Thread.sleep(long)

    使当前线程睡眠指定时间。这里的睡眠指的是暂停执行,并不会释放锁。时间到后,会自动进入RUNNABLE状态。

  • Object.wait(long)

    使线程进入TIMED_WAITING状态,会释放锁。经过指定时间后,自动唤醒,拥有去争夺锁的资格。

  • Thread.join(long)

    使当前线程执行指定时间,并且使线程进入TIMED_WAITING状态。

线程中断

当线程启动后不需要它继续执行下去的时候,需要线程中断机制。线程中断机制是一种协作机制,通过中断操作并不能直接终止一个线程,而是通知需要中断的线程自行处理。

  • Thread.interrupt()

    中断线程。并不会立即停止线程,而是设置线程的中断状态为true,默认为false

  • Thread.interrupted()

    测试当前线程是否被中断。调用一次这个方法会使中断状态设置为true,调用两次中断状态重新转变为false

  • Thread.isInterrupted()

    测试当前线程状态是否被中断,与上面方法不同的是不会影响线程的中断状态。

-------------本文结束感谢您的阅读-------------