线程生命周期
Categories:
Java的线程分为两类, 用户线程和守护线程
线程调度就是线程不同状态间的转换
在操作系统中,线程被视为轻量级的进程,所以线程状态其实和进程状态是一致的。
Java线程有如下状态
// Thread.State 源码
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
NEW
处于 NEW 状态的线程是刚创建 Thread
而尚未启动。这里的尚未启动指的是还没调用 Thread 实例的start()
方法。
private void testStateNew() {
Thread thread = new Thread(() -> {});
System.out.println(thread.getState()); // 输出 NEW
}
RUNNABLE
线程启动之后的状态
call thread.start()
will Causes this thread to begin execution; the Java Virtual Machine calls the run
method of this thread.
The result is that two threads are running concurrently: the current thread (which returns from the call to the start
method) and the other thread (which executes its run
method).
当前线程正在运行中。处于 RUNNABLE 状态的线程在 Java 虚拟机中运行
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
when recall a RUNNABLE thread, an IllegalThreadStateException
will throwed if the thread was already started.
Java 线程的RUNNABLE状态其实包括了操作系统线程的ready和running两个状态。
BLOCK
阻塞状态。处于 BLOCKED 状态的线程正等待锁(锁会在后面细讲)的释放以进入同步区。
WAITING
等待状态。处于等待状态的线程变成 RUNNABLE 状态需要其他线程唤醒。
Object.wait()
:使当前线程处于等待状态直到另一个线程唤醒它Thread.join()
:等待线程执行完毕,底层调用的是 Object 的 wait 方法,等待期间可以通过Object.notify()
/notifyAll()/Locksupport.unpark()
唤醒LockSupport.park()
:除非获得调用许可,否则禁用当前线程进行线程调度
TIMED_WAITING
超时等待状态。线程等待一个具体的时间,时间到后会被自动唤醒。
调用如下方法会使线程进入超时等待状态:
-
Thread.sleep(long millis)
:使当前线程睡眠指定时间 -
Object.wait(long timeout)
:线程休眠指定时间,等待期间可以通过Object.notify()
/notifyAll()/Locksupport.unpark()
唤醒 -
Thread.join(long millis)
:等待当前线程最多执行 millis 毫秒,如果 millis 为 0,则会一直执行 -
LockSupport.parkNanos(long nanos)
: 除非获得调用许可,否则禁用当前线程进行线程调度指定时间 -
LockSupport.parkUntil(long deadline)
:同上,也是禁止线程进行调度指定时间;
TERMINATED
终止状态
调度方法
等待与通知
Object.wait()
调用wait()
方法前线程必须持有对象的锁。
线程调用wait()
方法时,会释放当前的锁,直到有其他线程调用notify()
/notifyAll()
方法唤醒等待锁的线程。
需要注意的是,其他线程调用notify()
方法只会唤醒单个等待锁的线程,如有有多个线程都在等待这个锁的话不一定会唤醒到之前调用wait()
方法的线程。
同样,调用notifyAll()
方法唤醒所有等待锁的线程之后,也不一定会马上把时间片分给刚才放弃锁的那个线程,具体要看系统的调度。
Object.wait(long)
/Object.wait(long, int)
wait(long)
方法使线程进入 TIMED_WAITING 状态。这里的wait(long)
方法与无参方法 wait()相同的地方是,都可以通过其他线程调用notify()
或notifyAll()
方法来唤醒。
不同的地方是,有参方法wait(long)
就算其他线程不来唤醒它,经过指定时间 long 之后它会自动唤醒,拥有去争夺锁的资格。
Thread.join()
调用join()
方法,会一直等待这个线程执行完毕(转换为 TERMINATED 状态)。
休眠
Thread.sleep(long)
使当前线程睡眠指定时间。需要注意这里的“睡眠”只是暂时使线程停止执行,并不会释放锁。时间到后,线程会重新进入 RUNNABLE 状态。
让出执行权
yield()
:Thread 类中的静态方法,当一个线程调用 yield 方法时,实际是在暗示线程调度器,当前线程请求让出自己的 CPU,但是线程调度器可能会“装看不见”忽略这个暗示。
中断
中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序。
那么,我们究竟应该如何停止线程呢?
- 1、任务中一般都会有循环结构,只要用一个标记控制住循环,就可以结束任务。
- 2、如果线程处于了
冻结状态
,无法读取标记,此时可以使用interrupt()
方法将线程从冻结状态强制恢复到运行状态中
来,让线程具备CPU的执行资格。
Thread.interrupt(long)
作用是中断阻塞的线程。将会设置线程中断为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。 线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。 该方法只是改变中断状态,不会中断一个正在运行的线程。
因为该方法并不执行中断, 只是指示线程中断因此用户需要监视线程的执行结果来判断下一步操作 比如抛出interruptedException的方法, 监视线程的中断状态,一旦线程的中断状态被置为“中断状态”,就会抛出中断异常, 从而指示阻塞线程退出阻塞
引用: 博客园