您的位置:首页 > 编程语言 > Java开发

Java 线程 3 - 线程的生命周期

2017-11-01 09:55 399 查看
参考:

Java 线程 0 - 前言

java.lang Enum Thread.State

Java疯狂讲义 - 线程的生命周期

学习
Java
线程的生命周期以及相关的函数

主要内容:

线程生命周期

getState
isAlive


sleep
yield
join


interrupt
isInterrupted
interrupted


线程生命周期

参考:java.lang Enum Thread.State

A thread state. A thread can be in one of the following states:
* NEW - A thread that has not yet started is in this state.
* RUNNABLE - A thread executing in the Java virtual machine is in this state.
* BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
* WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
* TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
* TERMINATED - A thread that has exited is in this state.


Java
定义线程生命周期共有
6
种状态:

NEW


RUNNABLE


BLOCKED


WAITING


TIMED_WAITED


TERMINATED


各状态变化如下图所示:



NEW

使用
new
关键字创建新线程后,该线程就处于 新建 状态。此时,
Java
虚拟机为其分配了内存,并初始化了成员变量

RUNNABLE

调用
start
方法后,线程就处于 可运行 状态。
Java
虚拟机为其创建方法调用栈和程序计数器,但是线程是否已经运行取决于
Java
虚拟机线程调度器的调度,也就是说,当线程状态为
RUNNABLE
时,并不确定线程是否已经开始执行
run
方法


当没有足够的处理器资源时,线程调用
start
方法后并不会立即执行
run
方法。此时可以暂停当前线程
1
毫秒,即可让就绪线程立即开始运行

BLOCKED
WAITING
TIMED_WAITING

内部对象锁

参考:《Java核心技术 卷I - 14.5.5 synchronized关键字》

Java 1.0
开始,每一个
Java
对象都有一个内部锁。如果方法使用
synchronized
关键字声明,即使用内部对象锁来保护方法。所以,必须先获取对象的内部锁,才能调用该方法

BLOCKED

当一个线程试图获取一个对象的内部锁,但该锁已被其它线程持有,那么,该线程就处于 阻塞 状态,直到其它线程释放该锁,并且线程调度器允许该线程持有,此时线程处于非阻塞状态

WAITING
TIMED_WAITING

当线程等待另一个线程通知调度器一个条件(
condition
)时,该线程处于 等待 状态

即调用
Object.wait
或者
Thread.join
,或者使用
Lock
Condition
时,线程处于等待状态

如果线程除了等待另一个线程的通知外,还会计算等待时间,如果超过一定时间,自动回到 可运行 状态,那么此时线程进入的是 计时等待 状态

带有超时参数的方法:
Thread.sleep
Thread.wait
Thread.join
,以及
Lock.tryLock
Condition.await


TERMINATED

线程 终止 有两种情况:

正常运行
run
方法结束

run
方法中遇到一个未捕获异常而终止

《Java疯狂讲义 16.3 线程的生命周期》

《Java疯狂讲义》
中,将线程生命周期分为
5
个状态:

新建(
New


就绪(
Runnable


运行(
Running


阻塞(
Blocked


死亡(
Dead


其状态变化图如下图所示:



它将
Java
中的 可运行 状态分为了 就绪 和 运行 状态,等待处理器资源的属于 就绪 状态;已获得资源开始运行
run
方法的属于 运行 状态

将 阻塞/等待/计时等待 合并为 阻塞 状态

里面列出了多个处于阻塞状态的情况:

线程调用
sleep
方法主动放弃所占用的处理器资源

线程调用了一个阻塞式
IO
的方法,在该方法返回之前,该线程被阻塞

线程试图获取一个同步监视器,但该同步监视器被其它线程所占有

线程在等待某个通知(
notify


由上面可知,情况 1 属于 计时等待 状态,情况 2 属于 等待 状态,情况 3 属于 阻塞 状态,情况 4 属于 等待/计时等待 状态

解除上面处于 阻塞 状态的方法如下:

调用
sleep
方法的线程经过了指定时间

线程调用的阻塞式
IO
方法已经返回

线程成功地获得了试图获取的同步监视器

其它线程发出了通知

getState
isAlive

参考:

getState()

isAlive()

判断当前线程生命周期状态,可以使用方法
getState


/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}


判断线程是否存活,使用方法
isAlive


/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return  <code>true</code> if this thread is alive;
*          <code>false</code> otherwise.
*/
public final native boolean isAlive();


sleep
yield
join

参考:

sleep

yield

join

sleep

使用方法
sleep
可以暂停当前执行线程指定时间,调用此方法后,线程从 可运行 状态转向 计时等待 状态,其有两个重载函数:

public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException


通常仅指定暂停毫秒数(其精确性和准确性依赖于系统定时器和调度器)

/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param  millis
*         the length of time to sleep in milliseconds
*
* @throws  IllegalArgumentException
*          if the value of {@code millis} is negative
*
* @throws  InterruptedException
*          if any thread has interrupted the current thread. The
*          <i>interrupted status</i> of the current thread is
*          cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;

public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}

sleep(millis);
}


从重载方法实现中可看出,
Java
系统仅将暂停时间精确到毫秒级


yield

方法
yield
用于提示系统当前线程愿意放弃处理器资源,回到就绪状态,此时如果没有优先级比当前线程高或者相等的就绪线程的话,系统会重新将处理器资源分配给当前线程

/**
* A hint to the scheduler that the current thread is willing to yield
* its current use of a processor. The scheduler is free to ignore this
* hint.
*
* <p> Yield is a heuristic attempt to improve relative progression
* between threads that would otherwise over-utilise a CPU. Its use
* should be combined with detailed profiling and benchmarking to
* ensure that it actually has the desired effect.
*
* <p> It is rarely appropriate to use this method. It may be useful
* for debugging or testing purposes, where it may help to reproduce
* bugs due to race conditions. It may also be useful when designing
* concurrency control constructs such as the ones in the
* {@link java.util.concurrent.locks} package.
*/
public static native void yield();


对于调用线程来说,
yield
方法的使用并没有改变线程的状态(一直在 Runnable 状态)

join

join
方法有
3
种重载形式:

public final void join() throws InterruptedException
public final void join(long millis) throws InterruptedException
public final void join(long millis, int nanos) throws InterruptedException


如果线程
A
在线程
B
中调用了
join
方法,那么线程
B
需要等待线程
A
运行结束或者等待一段时间

public final void join() throws InterruptedException {
join(0);
}

/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param  millis
*         the time to wait in milliseconds
*
* @throws  IllegalArgumentException
*          if the value of {@code millis} is negative
*
* @throws  InterruptedException
*          if any thread has interrupted the current thread. The
*          <i>interrupted status</i> of the current thread is
*          cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;

if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}

public final synchronized void join(long millis, int nanos)
throws InterruptedException {

if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}

if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}

join(millis);
}


从重载方法中可知,最终调用的是
join(long millis)
。如果没有任何参数,表示当前线程需要等待调用线程运行结束;如果有输入时间参数(毫秒单位),那么等待一段时间后即可运行

join
方法使当前线程从 运行时 状态进入 等待/计时等待 状态


interrupt
isInterrupted
interrupted

参考:

interrupt

isInterrupted

interrupted

线程中断相关的函数有如下
3
个:

public void interrupt()
public boolean isInterrupted()
public static boolean interrupted()


其使用场景并没有特别理解,线程对象调用
interrupt()
方法后,仅仅设置了中断位,并没有进一步的操作(进一步的操作需要自己去定义,可以忽略中断,也可以进行其它操作)

而且如果遇到线程处于 阻塞/等待/计时等待 的状态下,还会抛出
InterruptedExcpetion


在知乎上找了几个资料:

线程的中断(interrupt)机制

Java里一个线程调用了Thread.interrupt()到底意味着什么?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: