线程的生命周期经过 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Bolocked)和死亡(Dead)
程序使用 new关键字 创建一个线程之后,该线程就 处于新建状态 ,仅仅由Java虚拟机为其 分配内存 ,并 初始化其成员变量的值 。 不会执行线程的线程执行体 。如 Thread thread = new Thread() 。
也称为 “可执行状态” ,线程对象调用 start() 方法后,该线程 处于就绪状态 。如 thread.start() 。Java虚拟机会为其 创建方法调用栈和程序计数器 (线程私有),处于就绪状态的线程并没有开始运行,只是 表示该线程可以运行 ,线程何时运行取决于JVM中线程调度器的调度。
处于就绪状态的线程 获得CPU ,开始执行 run()方法 的线程执行体,则该线程 处于运行状态 。(注意:线程只能从就绪状态进入到运行状态)
阻塞状态是线程因为某种原因 放弃了CPU的使用权 ,暂时停止运行,直到线程进入就绪状态,才有机会转到运行状态。当调用 sleep() 、一个阻塞式 IO方法 、同步锁、等待通知、 suspend()方法 挂起都会使线程进入阻塞状态。
sleep() 方法主动放弃所占用的处理器资源; IO方法 ,在该方法返回之前,该线程被阻塞; 同步监视器 ,但该同步监视器正被其他线程所持有; wait() )某个通知( notify() ); suspend() 方法将该线程挂起,但这个方法易造成死锁,应该避免使用。 线程从 阻塞状态解除 —— 进入就绪状态 的过程:
sleep()方法 的线程 经过了指定时间 ; resume() 恢复方法。 run() 或 call() 方法执行完成,线程正常结束; Exception 或 Error ; stop() 方法来结束该线程(该方法易造成死锁,不推荐使用) 可以通过 isAlive() 方法,线程对象的 isAlive() 方法返回true,即为线程存活;返回false,即为线程死亡。
线程处于 就绪、运行、阻塞状态 时, isAlive() 返回 true ;线程处于 新建、死亡状态 时, isAlive() 返回 false 。
当程序使用 new关键字 创建了一个线程后,该线程就处于新建状态,此时它和其他Java对象是一样的,只是由JVM为其分配内存,并初始化其成员变量的值(此时线程对象没有任何的行为,也不执行线程执行体)。
当线程对象调用了 start() 方法后,线程就处于就绪状态,JVM为其创建方法调用栈和程序计数器,处于这个状态中的线程还没有真正的开始运行,只是表示这个线程此时是一个可运行状态。何时能运行?取决于JVM的线程调度器的调度。
处于就绪状态的线程获取 CPU执行权限 ,开始执行 run() 方法的线程执行体,此时线程处于运行状态。(若只有一个CPU,任何时刻只能有一个线程处于运行状态,多线程处理任务时,会给人一种并发错觉,实际是CPU执行速度较快,多线程交织执行任务而已)
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
//若线程不是就绪状态,就抛出异常
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
//将线程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
//通过start0()方法启动线程
start0();
//设置线程启动的started标志位
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
start() 实际上通过本地方法 start0() 启动线程,会新运行一个线程,新线程会调用 run() 方法。
@Override
public void run() {
if (target != null) {
target.run();
}
}
target 是 Runnable对象 , run() 直接调用 Thread线程 的 Runnable成员 的 run() 方法,并不会新建一个线程。
public static native void sleep(long millis) throws InterruptedException public static void sleep(long millis, int nanos) throws InterruptedException
通常用法就是
//让当前线程睡眠1000毫秒,即暂定1s Thread.sleep(1000);
yield() 方法让当前正在执行的线程暂停,但 不会阻塞线程 ,只是让线程转入就绪状态。 yield() 方法让当前线程暂停,让系统的 线程调度重新调度一次 ,所以会出现当某个线程调用了yield()方法后,线程调度器又重新将它调度出来执行。 yield() 方法让当前线程暂停后,只有 优先级>=当前线程 的处于 就绪状态 的线程才能获取CPU执行权限。 public static native void yield(); :静态方法。 //让当前线程暂停 Thread.yield();
setPriority(int newPriority) 和 getPriority() 方法设置和返回指定线程的优先级。其中setPriority()方法的参数可以是一个整数(1-10之间),也可以是静态常量。 join()方法 join()
public final void join() throws InterruptedException public final synchronized void join(long millis) throws InterruptedException public final synchronized void join(long millis, int nanos) throws InterruptedException
public class JoinMethodTest {
public static void main(String[] args) {
System.out.println("main thread start");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread start");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("child thread finshed");
}
});
thread.start();
System.out.println("main thread finshed");
}
}
main thread start main thread finshed child thread start child thread finshed
可以从运行结果看出,main()主线程日志打印的很快,没有等待子线程打印就结束了。
public class JoinMethodTest {
public static void main(String[] args) {
System.out.println("main thread start");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread start");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("child thread finshed");
}
});
thread.start();
//加入join()方法等待子线程执行完毕,才执行主线程。
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main thread finshed");
}
}
main thread start child thread start child thread finshed main thread finshed
从运行结果可以看出, main thread finshed 结果是在最后打印的,加入join()方法等待子线程执行完毕,才执行主线程。
start() 方法启动线程,系统会将该线程对象的 run() 方法当作线程执行体来处理。 run() 方法,该方法会被立即执行,而在 run() 方法返回之前其他线程无法并发执行(系统会将线程对象的当作一个普通对象,将 run() 方法当作一个普通方法,而不是线程执行体。) start() 是启动线程,让线程从新建状态变为就绪状态;线程得到CPU时间片后,执行 run() 中的线程执行体; start() 只能调用一次; run() 可以重复调用。 start() ,系统会把 run() 方法当做线程执行体处理;如果直接调用 run() ,系统会把线程对象当作普通对象,此时 run() 也是一个普通方法,而不是线程执行体。run()方法只是类的一个普通方法而已,如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码。。 start() 源码中实际上通过本地方法 start0() 启动线程,会新运行一个线程,新线程会调用 run() 方法;而 run() 源码中 target 是 Runnable对象 , run() 直接调用 Thread线程 的 Runnable 成员的 run() 方法,并不会新建一个线程。