线程的生命周期通过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Bolocked)和死亡(Dead)java
程序使用new关键字
建立一个线程以后,该线程就处于新建状态
,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。不会执行线程的线程执行体。如Thread thread = new Thread()
。编程
也称为“可执行状态”
,线程对象调用start()
方法后,该线程处于就绪状态
。如thread.start()
。Java虚拟机会为其建立方法调用栈和程序计数器(线程私有),处于就绪状态的线程并无开始运行,只是表示该线程能够运行,线程什么时候运行取决于JVM中线程调度器的调度。多线程
处于就绪状态的线程得到CPU,开始执行run()方法
的线程执行体,则该线程处于运行状态
。(注意:线程只能从就绪状态进入到运行状态)并发
阻塞状态是线程由于某种缘由放弃了CPU的使用权
,暂时中止运行,直到线程进入就绪状态,才有机会转到运行状态。当调用sleep()
、一个阻塞式IO方法
、同步锁、等待通知、suspend()方法
挂起都会使线程进入阻塞状态。ide
sleep()
方法主动放弃所占用的处理器资源;IO方法
,在该方法返回以前,该线程被阻塞;同步监视器
,但该同步监视器正被其余线程所持有;wait()
)某个通知(notify()
);suspend()
方法将该线程挂起,但这个方法易形成死锁,应该避免使用。线程从阻塞状态解除——进入就绪状态的过程:函数
sleep()方法
的线程通过了指定时间;resume()
恢复方法。run()
或call()
方法执行完成,线程正常结束;Exception
或Error
;stop()
方法来结束该线程(该方法易形成死锁,不推荐使用)注意:this
能够经过isAlive()
方法,线程对象的isAlive()
方法返回true,即为线程存活;返回false,即为线程死亡。
线程处于就绪、运行、阻塞状态时,isAlive()
返回true
;线程处于新建、死亡状态时,isAlive()
返回false
。线程
当程序使用new关键字
建立了一个线程后,该线程就处于新建状态,此时它和其余Java对象是同样的,只是由JVM为其分配内存,并初始化其成员变量的值(此时线程对象没有任何的行为,也不执行线程执行体)。
当线程对象调用了start()
方法后,线程就处于就绪状态,JVM为其建立方法调用栈和程序计数器,处于这个状态中的线程尚未真正的开始运行,只是表示这个线程此时是一个可运行状态。什么时候能运行?取决于JVM的线程调度器的调度。
处于就绪状态的线程获取CPU执行权限
,开始执行run()
方法的线程执行体,此时线程处于运行状态。(若只有一个CPU,任什么时候刻只能有一个线程处于运行状态,多线程处理任务时,会给人一种并发错觉,实际是CPU执行速度较快,多线程交织执行任务而已)3d
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
:让当前正在执行的线程暂停millis毫秒,并进入阻塞状态。public static void sleep(long millis, int nanos) throws InterruptedException
:让当前正在执行的线程暂停millis毫秒+nanos毫微秒,并进入阻塞状态。(不多用)一般用法就是
//让当前线程睡眠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()方法
让一个线程等待另外一个线程完成的方法;就是将指定的线程加入到当前线程,这样两个交替执行的线程就变成了顺序执行的线程,如线程A调用了线程B的join()方法,则线程A会等待线程B执行完毕后才会继续执行本身。join()
方法由使用线程的程序调用,调用线程调用线程t的t.join()方法后将会被阻塞,直到线程t执行完毕,调用线程才能继续执行。通常就是用于主线程内,等待其余线程执行完毕后,再继续执行main()函数。public final void join() throws InterruptedException
:等待被join的线程执行完毕。public final synchronized void join(long millis) throws InterruptedException
:等待被join的线程的超时时间为millis毫秒。若是在millis毫秒内被join的线程还未结束执行流程,则调用线程再也不等待。public final synchronized void join(long millis, int nanos) throws InterruptedException
:等待被join的线程的时间最长为millis毫秒+nanos毫微秒。(不多用)代码
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()
方法,并不会新建一个线程。