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

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

二、线程状态源码

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 的使用



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
线程生命周期: 1. 创建线程:通过创建Thread对象或者实现Runnable接口创建线程; 2. 就绪状态:调用start()方法后,线程进入就绪状态,等待CPU调度执行; 3. 运行状态:当CPU调度到该线程时,线程进入运行状态; 4. 阻塞状态:线程因为某些原因(如等待IO操作完成、等待锁释放等)暂时停止执行,进入阻塞状态; 5. 终止状态:线程完成任务或者出现异常等原因结束执行,进入终止状态。 同步机制和锁: Java的同步机制主要包括synchronized关键字和Lock接口。它们都可以用来实现线程之间的同步,避免多个线程同时修改共享资源导致的数据不一致问题。 synchronized关键字用来修饰方法或代码块,保证同一时间只有一个线程可以执行这个方法或代码块。当一个线程进入synchronized方法或代码块时,它会尝试获取锁,如果锁已经被其他线程获取,则该线程会阻塞等待锁的释放。 Lock接口则提供了更加灵活的锁机制,它可以实现公平锁或者非公平锁、可重入锁等。与synchronized不同,Lock需要手动获取锁和释放锁,使用起来更加灵活。 线程池: 线程池是一种管理和复用线程资源的机制,通过预先创建一定数量的线程,将任务分配给这些线程执行,避免了频繁的创建和销毁线程的开销,提高了程序的性能和稳定性。 Java提供了ThreadPoolExecutor类来实现线程池,可以设置核心线程数、最大线程数、任务队列、拒绝策略等参数,以满足不同场景下的需求线程池还可以优化线程的调度和资源使用,提高程序的并发能力和吞吐量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值