线程生命周期,锁及cpu资源需求

本文详细介绍了Java线程的六种生命周期状态,包括创建、可执行、阻塞、等待、超时等待及终止状态,并解释了每种状态的含义及对应的源码。此外,还探讨了线程上下文切换的概念及其带来的开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、线程的生命周期(图)

二、线程状态源码

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

三、线程状态描述

NEW-创建状态

    初始创建线程,比如在主线程中用new关键字创建了一个线程对象。仅仅在堆中分配了内存

RUNNABLE-可执行状态

    可执行状态,可以说包含了2种情况,线程start后进入此状态。当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

 public synchronized void start()

    就绪(ready):在没有获取到CPU调度权(执行时间)时,线程在准备就绪中

    运行(running):获取到CPU调度权(执行时间)后,运行程序

yield方法会让线程从运行(running)退回到就绪(ready)

  public static native void yield();

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

注意:调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的

BLOCKED-阻塞状态

    当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。即多个线程同时调用同步方法块或者同步方法时,未能获取锁的线程处理此状态。

TIMED_WAITING-超时等待状态

调用以下方法,会使用线程进入此超时等待状态

//Thread类-休眠(交出CPU执行权限,不会释放锁)
public static native void sleep(long millis) throws InterruptedException

//Thread类-超时等待(内部调用Object#wait方法,交出CPU执行权限,会释放锁)
public final synchronized void join(long millis)throws InterruptedException

//Object类-超时等待(交出CPU执行权限,会释放锁)
public final native void wait(long timeout) throws InterruptedException

//LockSupport类
public static void parkNanos(Object blocker, long nanos)

//LockSupport类
public static void parkUntil(long deadline)

注意:

sleep相当于让线程睡眠,sleep方法不会释放锁,只是交出CPU,让CPU去执行其他的任务。

wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

WAITING-等待状态

调用以下方法进入此状态

//Thread类-一直等待(内部调用Object#wait方法,会释放锁)
public final synchronized void join()throws InterruptedException

//Object类-一直等待(会释放锁)
public final void wait() throws InterruptedException

//LockSupport类
public static void park(Object blocker)

TERMINATED-终止状态

三、上下文切换

    对于单核CPU来说(对于多核CPU,此处就理解为一个核),CPU在一个时刻只能运行一个线程,当在运行一个线程的过程中转去运行另外一个线程,这个叫做线程上下文切换(对于进程也是类似)。

    由于可能当前线程的任务并没有执行完毕,所以在切换时需要保存线程的运行状态,以便下次重新切换回来时能够继续切换之前的状态运行。举个简单的例子:比如一个线程A正在读取一个文件的内容,正读到文件的一半,此时需要暂停线程A,转去执行线程B,当再次切换回来执行线程A的时候,我们不希望线程A又从文件的开头来读取。

    因此需要记录线程A的运行状态,那么会记录哪些数据呢?因为下次恢复时需要知道在这之前当前线程已经执行到哪条指令了,所以需要记录程序计数器的值,另外比如说线程正在进行某个计算的时候被挂起了,那么下次继续执行的时候需要知道之前挂起时变量的值时多少,因此需要记录CPU寄存器的状态。所以一般来说,线程上下文切换过程中会记录程序计数器、CPU寄存器状态等数据。

    说简单点的:对于线程的上下文切换实际上就是 存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。 虽然多线程可以使得任务执行的效率得到提升,但是由于在线程切换时同样会带来一定的开销代价,并且多个线程会导致系统资源占用的增加,所以在进行多线程编程时要注意这些因素。

四、方法与CPU执行权限,同步锁,堆内存占用对比

类#方法

功能

cpu执行权限

同步锁

堆内存

备注

Object#notify

通知等待结束

 

占有

 

只有其所在同步方法/块执行完才释放

Object#wait

对象等待

释放

释放

 

 

Thread#join

等待

释放

释放 

 

 

Thread#sleep

休眠

释放

占有

 

 

Thread#yield

放弃当前CPU权限

释放

占有

 

 

Thread#stop

立即停止线程

释放

释放

 

立即释放同步锁,状态可能不一致

Thread#suspend

暂停线程

释放

占有

 

独占锁,使用不当会死锁

Thread#resume

恢复线程运行

 

 

 

 


--------------------------------

引用原文列表:

  1. 《JAVA多线程编程核心技术》
  2. Java Thread 的使用



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值