Java 线程 3 - 线程的生命周期
2017-11-01 09:55
399 查看
参考:
Java 线程 0 - 前言
java.lang Enum Thread.State
Java疯狂讲义 - 线程的生命周期
学习
主要内容:
线程生命周期
各状态变化如下图所示:
使用
调用
当没有足够的处理器资源时,线程调用
从
当一个线程试图获取一个对象的内部锁,但该锁已被其它线程持有,那么,该线程就处于 阻塞 状态,直到其它线程释放该锁,并且线程调度器允许该线程持有,此时线程处于非阻塞状态
当线程等待另一个线程通知调度器一个条件(
即调用
如果线程除了等待另一个线程的通知外,还会计算等待时间,如果超过一定时间,自动回到 可运行 状态,那么此时线程进入的是 计时等待 状态
带有超时参数的方法:
线程 终止 有两种情况:
正常运行
在
新建(
就绪(
运行(
阻塞(
死亡(
其状态变化图如下图所示:
它将
将 阻塞/等待/计时等待 合并为 阻塞 状态
里面列出了多个处于阻塞状态的情况:
线程调用
线程调用了一个阻塞式
线程试图获取一个同步监视器,但该同步监视器被其它线程所占有
线程在等待某个通知(
由上面可知,情况 1 属于 计时等待 状态,情况 2 属于 等待 状态,情况 3 属于 阻塞 状态,情况 4 属于 等待/计时等待 状态
解除上面处于 阻塞 状态的方法如下:
调用
线程调用的阻塞式
线程成功地获得了试图获取的同步监视器
其它线程发出了通知
参考:
getState()
isAlive()
判断当前线程生命周期状态,可以使用方法
判断线程是否存活,使用方法
参考:
sleep
yield
join
通常仅指定暂停毫秒数(其精确性和准确性依赖于系统定时器和调度器)
从重载方法实现中可看出,
对于调用线程来说,
如果线程
从重载方法中可知,最终调用的是
参考:
interrupt
isInterrupted
interrupted
线程中断相关的函数有如下
其使用场景并没有特别理解,线程对象调用
而且如果遇到线程处于 阻塞/等待/计时等待 的状态下,还会抛出
在知乎上找了几个资料:
线程的中断(interrupt)机制
Java里一个线程调用了Thread.interrupt()到底意味着什么?
Java 线程 0 - 前言
java.lang Enum Thread.State
Java疯狂讲义 - 线程的生命周期
学习
Java线程的生命周期以及相关的函数
主要内容:
线程生命周期
getState和
isAlive
sleep,
yield和
join
interrupt,
isInterrupted和
interrupted
线程生命周期
参考:java.lang Enum Thread.StateA 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()到底意味着什么?
相关文章推荐
- java中线程的生命周期
- java 多线程 入门 线程生命周期图
- Java线程的生命周期
- JAVA线程的生命周期
- java-线程的生命周期
- Java学习笔记之线程的生命周期
- Java线程的生命周期小结
- java的四大作用域及线程的生命周期
- java学习11--线程创建的两种方式,生命周期以及守护线程
- java多线程系列_线程的生命周期(4)
- Java 多线程(三) 线程的生命周期及优先级
- JAVA多线程编程(三)——线程的生命周期(sleep,join,interrupt)
- Java--线程生命周期,线程控制
- Java--线程的分类和生命周期
- Java多线程、线程的生命周期和状态控制
- [疯狂Java]多线程:线程的生命周期
- 第24章 java线程(3)-线程的生命周期
- java多线程之线程的生命周期
- java--线程的生命周期
- java 线程的生命周期详解