精华内容
下载资源
问答
  • Java线程6种状态及切换(透彻讲解)

    万次阅读 多人点赞 2016-12-24 16:57:03
    Java中线程状态分为6种。 1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。 2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,...

    Java中线程的状态分为6种。

    1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
    2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
    线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
    3. 阻塞(BLOCKED):表示线程阻塞于锁。
    4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
    5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
    6. 终止(TERMINATED):表示该线程已经执行完毕。

    这6种状态定义在Thread类的State枚举中,可查看源码进行一一对应。

    一、线程的状态图     线程状态图

    二、状态详细说明

    1. 初始状态(NEW)

    实现Runnable接口和继承Thread可以得到一个线程类,new一个实例出来,线程就进入了初始状态。

    2.1. 就绪状态(RUNNABLE之READY)

    1. 就绪状态只是说你资格运行,调度程序没有挑选到你,你就永远是就绪状态。
    2. 调用线程的start()方法,此线程进入就绪状态。
    3. 当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。
    4. 当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入就绪状态。
    5. 锁池里的线程拿到对象锁后,进入就绪状态。

    2.2. 运行中状态(RUNNABLE之RUNNING)

    线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一的一种方式。

    3. 阻塞状态(BLOCKED)

    阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。

    4. 等待(WAITING)

    处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。

    5. 超时等待(TIMED_WAITING)

    处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。

    6. 终止状态(TERMINATED)

    1. 当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
    2. 在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

    三、等待队列

    • 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) 代码段内。
    • 与等待队列相关的步骤和图

    1. 线程1获取对象A的锁,正在使用对象A。
    2. 线程1调用对象A的wait()方法。
    3. 线程1释放对象A的锁,并马上进入等待队列。
    4. 锁池里面的对象争抢对象A的锁。
    5. 线程5获得对象A的锁,进入synchronized块,使用对象A。
    6. 线程5调用对象A的notifyAll()方法,唤醒所有线程,所有线程进入同步队列。若线程5调用对象A的notify()方法,则唤醒一个线程,不知道会唤醒谁,被唤醒的那个线程进入同步队列。
    7. notifyAll()方法所在synchronized结束,线程5释放对象A的锁。
    8. 同步队列的线程争抢对象锁,但线程1什么时候能抢到就不知道了。 

    四、同步队列状态

    • 当前线程想调用对象A的同步方法时,发现对象A的锁被别的线程占有,此时当前线程进入同步队列。简言之,同步队列里面放的都是想争夺对象锁的线程。
    • 当一个线程1被另外一个线程2唤醒时,1线程进入同步队列,去争夺对象锁。
    • 同步队列是在同步的环境下才有的概念,一个对象对应一个同步队列
    • 线程等待时间到了或被notify/notifyAll唤醒后,会进入同步队列竞争锁,如果获得锁,进入RUNNABLE状态,否则进入BLOCKED状态等待获取锁。

    五、几个方法的比较

    1. Thread.sleep(long millis),一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。作用:给其它线程执行机会的最佳方式。
    2. Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的CPU时间片,但不释放锁资源,由运行状态变为就绪状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。该方法与sleep()类似,只是不能由用户指定暂停多长时间。
    3. thread.join()/thread.join(long millis),当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程一般情况下进入RUNNABLE状态,也有可能进入BLOCKED状态(因为join是基于wait实现的)。
    4. obj.wait(),当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout) timeout时间到自动唤醒。
    5. obj.notify()唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程。
    6. LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.parkUntil(long deadlines), 当前线程进入WAITING/TIMED_WAITING状态。对比wait方法,不需要获得锁就可以让线程进入WAITING/TIMED_WAITING状态,需要通过LockSupport.unpark(Thread thread)唤醒。

    六、疑问

    1. 等待队列里许许多多的线程都wait()在一个对象上,此时某一线程调用了对象的notify()方法,那唤醒的到底是哪个线程?随机?队列FIFO?or sth else?Java文档就简单的写了句:选择是任意性的(The choice is arbitrary and occurs at the discretion of the implementation)。
    展开全文
  • 线程的六种状态及其状态的转换

    万次阅读 2018-10-04 18:15:26
    1.线程自身信息 线程运行的过程会产生很多信息,这些信息都保... 线程的优先级:getPriority,线程优先级从1-10,其中数字越大表示优先级别越高,同时获得JVM调度执行的可能性越大,JDK内置了三常见的状态: //...

    1.线程自身信息

    线程运行的过程会产生很多信息,这些信息都保存在Thread类中的成员变量里面,常见的有:

    • 线程的ID是唯一标识getId()
    • 线程的名称:getName(),如果不设置线程名称默认为“Thread-xx”
    • 线程的优先级:getPriority,线程优先级从1-10,其中数字越大表示优先级别越高,同时获得JVM调度执行的可能性越大,JDK内置了三种常见的状态:
    //最小优先级
    public final static int MIN_PRIORITY = 1;
     
    //一般优先级
    public final static int NORM_PRIORITY = 5;
     
    //最大优先级
    public final static int MAX_PRIORITY = 10;

     一般不推荐设置线程的优先级,如果进行设置了非法的优先级程序就会出现IllegalArgumentException异常。

    2.线程的几个状态

    1.Java线程有六种状态

    public enum State {
        //线程刚创建
        NEW,
     
        //在JVM中正在运行的线程
        RUNNABLE,
     
        //线程处于阻塞状态,等待监视锁,可以重新进行同步代码块中执行
        BLOCKED,
     
        //等待状态
        WAITING,
     
        //调用sleep() join() wait()方法可能导致线程处于等待状态
        TIMED_WAITING,
     
        //线程执行完毕,已经退出
        TERMINATED;
    }

    上面六种状态图如下:

    2.线程状态的解释

    1.当线程继承Thread或者实现了Runnable创建了线程对象后,当new线程对象过后线程就进入了初始的状态。

    2.当线程对象调用了start()方法的时候,线程启动进入可运行的状态。

    3.线程进入可运行状态后,如果逻辑完成那么线程将会终结,如果没有执行完毕中间JVM分配时间片用完,将进入可运行状态,一旦线程被JVM选中则立即执行。

    4.运行状态的情况比较复杂
    第一:线程如果执行run() main()方法结束后,完成逻辑,线程就进入Terminated

    第二:当线程调用sleep()或者join()方法就会进入Blocked状态,但是要注意的是阻塞的线程是不释放当前所占有的系统资源,当sleep()结束或者join()等待其他线程来到,当前线程则进入Runnable状态等待JVM分配资源。

    第三:当线程进入Runnable状态,但是还没有开始运行的时候,此时发现需要的资源处于同步状态synchronized,这个时候线程将会进入Time waiting,JVM会使用队列对这些线程进行控制,既先进行Time waiting的线程会先得到JVM资源进行执行进入Waiting

    第四:如果处于Runnable的线程调用yield()让出JVM资源,那么就会进入New状态和其他New状态线程进行竞争重新进入Runnable

    第五:如果当前线程调用wait()方法,则当前线程进入Time waiting但是这个时候当前线程会释放所占有的JVM资源,进入这个状态过后是不能自动唤醒的,必须调用notify()或者notifyAll()方法,线程进入Waiting。

    3.案例解释 

    案例:用案例解释线程的六种运行状态,其中Pig类实现Runnable接口,逻辑是打印当前运行的线程信息,
    每隔一秒打印一次。在Main方法中启动十个Pig线程设置相应的线程优先级别,并且将初始的线程状态
    保存到线程状态数组中,在运行的过程判断当前线程状态和初始状态是否相同,如果不同则打印当前线
    程的信息保存到日志文件中。

     

    import java.io.FileWriter;
    import java.io.PrintWriter;
    import java.lang.Thread.State;
    import java.util.concurrent.TimeUnit;
    
    class Pig implements Runnable {
     
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    //线程进行休眠一秒
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //打印当前执行线程信息
                System.out.println("ThreadName :  "+ Thread.currentThread().getName());
            }
        }
    }
     
    public class App {
        public static void main(String[] args) throws Exception {
            // 创建现成数组
            Thread[] taskArr = new Thread[10];
     
            // 线程状态数组
            Thread.State[] threadStates = new Thread.State[10];
     
            // 设置线程的状态
            for (int i = 0; i < 10; i++) {
                taskArr[i] = new Thread(new Pig());
     
                // 分别设置状态
                if ((i % 3) == 0) {
                    taskArr[i].setPriority(Thread.NORM_PRIORITY);
                } else if ((i % 3) == 1) {
                    taskArr[i].setPriority(Thread.MIN_PRIORITY);
                } else if ((i % 3) == 2) {
                    taskArr[i].setPriority(Thread.MAX_PRIORITY);
                }
            }
     
            // 将线程信息写入到文件中便于分析
            FileWriter fWriter = new FileWriter("F:/log.txt");
            PrintWriter pWriter = new PrintWriter(fWriter);
     
            // 循环遍历获取线程的信息
            for (int i = 0; i < 10; i++) {
                pWriter.println("线程  "+ i + " 状态:" + taskArr[i].getState());
     
                // 将当前线程状态保存到状态数组中
                threadStates[i] = taskArr[i].getState();
            }
     
            // 启动线程
            for (int i = 0; i < 10; i++) {
                taskArr[i].start();
            }
     
            // 在运行过程中如果线程的状态和初始状态不一样就将状态变化过程写入到文件中
            boolean finish = false;
     
            while (!finish) {
                for (int i = 0; i < 10; i++) {
                    // 线程状态发生变化
                    if (taskArr[i].getState() != threadStates[i]) {
                        // 打印线程当前信息
                        printThreadMsg(pWriter, taskArr[i], threadStates[i]);
     
                        // 将当前线程状态保存到线程状态数组中
                        threadStates[i] = taskArr[i].getState();
                    }
                }
                finish = true;
                for (int i = 0; i < 10; i++) {
                    finish = finish && (taskArr[i].getState() == State.TERMINATED);
                }
            }
        }
     
        /**
         * 打印当前线程的信息
         * @param pWriter
         * @param thread
         * @param state
         */
        private static void printThreadMsg(PrintWriter pWriter, Thread thread, State state) {
            pWriter.println("*********************************************************");
            pWriter.println("线程ID:  "+ thread.getId() +"  线程名称: "+ thread.getName());
            pWriter.println("线程优先级: "+ thread.getPriority());
            pWriter.println("线程过去状态:" + state);
            pWriter.println("线程当前状态: "+ thread.getState());
            pWriter.println("*********************************************************");
        }
    }
    

     

     

    分析上面的部分执行结果就可以看出当Pig线程进行休眠的时候,就会导致其他线程状态的变换,其中过去状态和当前状态可以明显的反应出线程状态切换。 

    展开全文
  • 答案是6种!!! 那为什么有的地方说是5种呢,那这一定是将操作系统层面的线程状态搞混了。 下面我们就分别介绍一下java线程的6种状态以及操作系统层面的5种状态: 1、java线程状态 java线程有6种状态,我们先来一个...

    背景

    先来解答一个世界级难题:

    java线程有多少种状态?

    答案是6种!!!

    那为什么有的地方说是5种呢,那这一定是将操作系统层面的线程状态搞混了。

    下面我们就分别介绍一下java线程的6种状态以及操作系统层面的5种状态:

    1、java线程状态

    java线程有6种状态,我们先来一个官方的依据

    public class Thread implements Runnable {
      public enum State {
            /**
             * Thread state for a thread which has not yet started.
             * <p>
             *  尚未启动的线程的线程状态。
             * 
             */
            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.
             * <p>
             * 可运行线程的线程状态。处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待来自操作系统的其他资源,例如处理器。
             * 
             */
            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}.
             * <p>
             *  线程阻塞等待监视器锁的线程状态。处于阻塞状态的线程在调用{@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.
             * <p>
             *  等待线程的线程状态。线程由于调用以下方法之一而处于等待状态:
             * <ul>
             *  <li> {@ link Object#wait()Object.wait}没有超时</li> <li> {@ link #join()Thread.join}没有超时</li> <li> {@ link LockSupport #park()LockSupport.park}
             *  </li>。
             * </ul>
             * 
             *  <p>处于等待状态的线程正在等待另一个线程执行特定操作。
             * 
             *  例如,在对象上调用<tt> Object.wait()</tt>的线程正在等待另一个线程调用<tt> Object.notify()</tt>或<tt> Object.notifyAll )</tt>
             * 。
             * 调用<tt> Thread.join()</tt>的线程正在等待指定的线程终止。
             * 
             */
            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>
             * <p>
             *  具有指定等待时间的等待线程的线程状态。由于调用指定正等待时间的以下方法之一,线程处于定时等待状态:
             * <ul>
             * <li> {@ link #sleep Thread.sleep} </li> <li> {@ link Object#wait(long)Object.wait} with timeout </li>
             *  <li> {@ link #join .join} with timeout </li> <li> {@ link LockSupport#parkNanos LockSupport.parkNanos}
             *  </li> <li> {@ link LockSupport#parkUntil LockSupport.parkUntil}。
             * </ul>
             */
            TIMED_WAITING,
    
            /**
             * Thread state for a terminated thread.
             * The thread has completed execution.
             * <p>
             *  终止线程的线程状态。线程已完成执行。
             * 
             */
            TERMINATED;
        }
    }
    

    简单来介绍一下6种状态:

    1))NEW:初始状态,线程被构建,但是还没有调用 start 方法;

    2)RUNNABLED:运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中” ;

    3)BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了 CPU 使用权,阻塞也分为几种情况 :

    • 等待阻塞:运行的线程执行了 Thread.sleepwait()join() 等方法JVM 会把当前线程设置为等待状态,当 sleep 结束、join 线程终止或者线程被唤醒后,该线程从等待状态进入到阻塞状态,重新抢占锁后进行线程恢复;

    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程锁占用了,那么jvm会把当前的线程放入到锁池中 ;

    • 其他阻塞:发出了 I/O请求时,JVM 会把当前线程设置为阻塞状态,当 I/O处理完毕则线程恢复;

    4)WAITING:等待状态,没有超时时间,要被其他线程或者有其它的中断操作;

    执行wait()、join()、LockSupport.park();

    5)TIME_WAITING:超时等待状态,超时以后自动返回;

    执行 Thread.sleep(long)、wait(long)、join(long)、LockSupport.park(long)、LockSupport.parkNanos(long)、LockSupport.parkUntil(long)

    6)TERMINATED:终止状态,表示当前线程执行完毕 。

    2、线程状态间的转换

    借一个图来描述:

    C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200526103703738.png

    具体的转换场景,图中描述的比较清楚,此处不再详细赘述。

    注意:

    1)sleep、join、yield时并不释放对象锁资源,在wait操作时会释放对象资源,wait在被notify/notifyAll唤醒时,重新去抢夺获取对象锁资源。

    2)sleep可以在任何地方使用,而wait,notify,notifyAll只能在同步控制方法或者同步控制块中使用。

    3)调用obj.wait()会立即释放锁,以便其他线程可以执行notify(),但是notify()不会立刻立刻释放sycronized(obj)中的对象锁,必须要等notify()所在线程执行完sycronized(obj)同步块中的所有代码才会释放这把锁。然后供等待的线程来抢夺对象锁。

    3、java代码中查看线程状态

    我们可以通过打印堆栈信息来查看线程的状态,下面举一个实例:

    public class ThreadState {
    
        public static void main(String[] args) {
            new Thread(()->{
                while(true){
                    try {
                        TimeUnit.SECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"thread01_status").start();  //阻塞状态
    
            new Thread(()->{
                while(true){
                    synchronized (ThreadState.class){
                        try {
                            ThreadState.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            },"thread02_status").start(); //阻塞状态
    
            new Thread(new BlockedDemo(),"BLOCKED-DEMO-01").start();
            new Thread(new BlockedDemo(),"BLOCKED-DEMO-02").start();
    
        }
        static class BlockedDemo extends  Thread{
            @Override
            public void run() {
                synchronized (BlockedDemo.class){
                    while(true){
                        try {
                            TimeUnit.SECONDS.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    
    

    通过打印堆栈信息来查看:(我使用的是IDEA,也可以直接用cmd命令打开命令窗口查看,效果是一样的)

    1)获取java进程的pid;

    S:\workspace\study\concurrent\thread-demo>jps
    23328 Launcher
    5376 ThreadState
    14700
    19708 Jps
    
    

    2)根据上一步骤获得的 pid,继续输入 jstack pidjstack是 java 虚拟机自带的一种堆栈跟踪工具。jstack用于
    打印出给定的 java 进程 ID 或 core file 或远程调试服务的 Java 堆栈信息)

    S:\workspace\study\concurrent\spring-boot-thread-demo>jstack 5376
    2020-05-26 11:19:31
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):
    
    "DestroyJavaVM" #19 prio=5 os_prio=0 tid=0x0000000002e44000 nid=0x5788 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "thread05_status" #18 prio=5 os_prio=0 tid=0x000000001f703000 nid=0x5efc waiting for monitor entry [0x00000000202df000]
       java.lang.Thread.State: `BLOCKED (on object monitor)`
            at com.example.springbootthreaddemo.demo02.ThreadState$BlockedDemo.run(ThreadState.java:49)
            - waiting to lock <0x000000076c0dc148> (a java.lang.Class for com.example.springbootthreaddemo.demo02.ThreadState$BlockedDemo)
            at java.lang.Thread.run(Thread.java:748)
    
    "thread04_status" #16 prio=5 os_prio=0 tid=0x000000001f701000 nid=0x52e0 waiting on condition [0x00000000201df000]
       java.lang.Thread.State:` TIMED_WAITING (sleeping)`
            at java.lang.Thread.sleep(Native Method)
            at java.lang.Thread.sleep(Thread.java:340)
            at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
            at com.example.springbootthreaddemo.demo02.ThreadState$BlockedDemo.run(ThreadState.java:49)
            - locked <0x000000076c0dc148> (a java.lang.Class for com.example.springbootthreaddemo.demo02.ThreadState$BlockedDemo)
            at java.lang.Thread.run(Thread.java:748)
    
    "thread03_status" #14 prio=5 os_prio=0 tid=0x000000001f715000 nid=0x4fc4 runnable [0x00000000200df000]
       java.lang.Thread.State: `RUNNABLE`
            at com.example.springbootthreaddemo.demo02.ThreadState.lambda$main$2(ThreadState.java:35)
            at com.example.springbootthreaddemo.demo02.ThreadState$$Lambda$3/935044096.run(Unknown Source)
            at java.lang.Thread.run(Thread.java:748)
    
    "thread02_status" #13 prio=5 os_prio=0 tid=0x000000001f714000 nid=0x4748 in Object.wait() [0x000000001ffdf000]
       java.lang.Thread.State:` WAITING (on object monitor)`
            at java.lang.Object.wait(Native Method)
            - waiting on <0x000000076bc73f08> (a java.lang.Class for com.example.springbootthreaddemo.demo02.ThreadState)
            at java.lang.Object.wait(Object.java:502)
            at com.example.springbootthreaddemo.demo02.ThreadState.lambda$main$1(ThreadState.java:26)
            - locked <0x000000076bc73f08> (a java.lang.Class for com.example.springbootthreaddemo.demo02.ThreadState)
            at com.example.springbootthreaddemo.demo02.ThreadState$$Lambda$2/443308702.run(Unknown Source)
            at java.lang.Thread.run(Thread.java:748)
    
    "thread01_status" #12 prio=5 os_prio=0 tid=0x000000001f711000 nid=0xb28 waiting on condition [0x000000001fedf000]
       java.lang.Thread.State: `TIMED_WAITING (sleeping)`
            at java.lang.Thread.sleep(Native Method)
            at java.lang.Thread.sleep(Thread.java:340)
            at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
            at com.example.springbootthreaddemo.demo02.ThreadState.lambda$main$0(ThreadState.java:15)
            at com.example.springbootthreaddemo.demo02.ThreadState$$Lambda$1/205797316.run(Unknown Source)
            at java.lang.Thread.run(Thread.java:748)
    

    从上面的信息中可以看到:

    1)thread01_status:状态为TIMED_WAITING,该线程是执行了sleep(),所以处于线程休眠状态;

    2)thread02_status:状态为WAITING,该线程是执行了wait(),所以处于线程等待状态;

    3)thread03_status:状态为RUNNABLE,该线程是正常运行中,处于运行状态;

    4)thread04_status:状态为TIMED_WAITING,该线程执行了同步代码块,它先获取到了BlockedDemo的类锁,执行了sleep(),所以处于线程等待状态;

    5)thread05_status:因为线程thread04_status获取到的类锁没有释放,所以thread05_status在执行synchronized(BlockedDemo.class)时是阻塞的,所以为BLOCKED状态。

    4、操作系统层面线程状态

    ​ 很多人会把操作系统层面的线程状态与java线程状态混淆,所以导致有的文章中把java线程状态写成是5种,在此我们说清楚一个问题,java线程状态是6个,操作系统层面的线程状态是5种。如下图所示:

    在这里插入图片描述
    下面分别介绍一下这5种状态:

    1)new :一个新的线程被创建,等待该线程被调用执行;

    2)ready :表示线程已经被创建,正在等待系统调度分配CPU使用权,或者时间片已用完,此线程被强制暂停,等待下一个属于它的时间片到来。

    3)running :表示线程获得了CPU使用权,正在占用时间片,正在进行运算中;

    4)waiting :表示线程等待(或者说挂起),等待某一事件(如IO或另一个线程)执行完,让出CPU资源给其他线程使用;

    5)terminated :一个线程完成任务或者其他终止条件发生,该线程终止进入退出状态,退出状态释放该线程所分配的资源。

    需要注意的是,操作系统中的线程除去new 和terminated 状态,一个线程真实存在的状态是ready 、running、waiting 。

    结语

    至此,我们就把java线程状态以及操作系统层面的线程状态说清了,是不是以后再也不会混淆了,希望能帮助到大家。

    展开全文
  • 详细介绍了Java线程6种状态,以及状态之间的转换。

    详细介绍了Java线程的6中状态,以及状态之间的转换。


    本文基于JDK1.8。

    1 线程状态(生命周期)

    1.1 源码中的状态

    关于Java线程的状态,网上说法很多,有五种、六种甚至七种,本文采用Java官方的线程状态分类。

    实际上,官方一共给出了六种线程状态,我们来看看源码便可知:

        public class Thread implements Runnable {
            //线程的状态以枚举的方式定义在Thread类的内部
            /**
             * A thread state.  A thread can be in one of the following states:
             * <ul>
             * <li>{@link #NEW}<br>
             *     A thread that has not yet started is in this state.
             *     </li>
             * <li>{@link #RUNNABLE}<br>
             *     A thread executing in the Java virtual machine is in this state.
             *     </li>
             * <li>{@link #BLOCKED}<br>
             *     A thread that is blocked waiting for a monitor lock
             *     is in this state.
             *     </li>
             * <li>{@link #WAITING}<br>
             *     A thread that is waiting indefinitely for another thread to
             *     perform a particular action is in this state.
             *     </li>
             * <li>{@link #TIMED_WAITING}<br>
             *     A thread that is waiting for another thread to perform an action
             *     for up to a specified waiting time is in this state.
             *     </li>
             * <li>{@link #TERMINATED}<br>
             *     A thread that has exited is in this state.
             *     </li>
             * </ul>
             *
             * <p>
             * A thread can be in only one state at a given point in time.
             * These states are virtual machine states which do not reflect
             * any operating system thread states.
             *
             * @since   1.5
             * @see #getState
             */
            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.
                 * <p>
                 * 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;
            }
        }
    

    从源码可以看出,Java语言定义了6种线程状态,作为内部枚举保存在Thread类中。这里我建议大家采用这六种状态,当然也可以按照自己的理解来。下面来解释一下每一种状态。

    1.2 状态解释

    在任意一个时间点,一个线程只能有且只有其中的一种状态,这6种状态分别如下:

    1. 新建(NEW):创建后尚未启动的线程处于这种状态。
    2. 运行(RUNNABLE):调用start()方法,RUNNABLE包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间(该线程已经获取了除CPU资源外的其他资源,等待获取CPU 资源后才会真正处于运行状态)。

    官方为什么不将这两种状态分开呢?有种可能是:线程在这Running和Ready两种状态之间的时长太短了,现代cpu采用轮询式时间片调度,大部分线程Running和Ready的时间都非常短暂,因此考虑将这两种状态合并为RUNNABLE状态。

    1. 无限期等待(WAITING):处于这种状态的线程不会被分配CPU执行时间,它们要等待被其他线程显式地唤醒。以下方法会让线程陷入无限期的等待状态:
    1. 没有设置Timeout参数的Object.wait()方法。
    2. 没有设置Timeout参数的Thread.join()方法。
    3. LockSupport.park()方法。
    1. 限期等待(TIMED_WAITING):处于这种状态的线程也不会被分配CPU执行时间,不过无须等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态:
    1. Thread.sleep(long millis)方法。
    2. 设置了Timeout参数的Object.wait()方法。
    3. 设置了Timeout参数的Thread.join()方法。
    4. LockSupport.parkNanos()方法。
    5. LockSupport.parkUntil()方法。
    1. 阻塞(BLOCKED):线程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程获得锁的时候可能发生,比如synchronized之外;而“等待状态”则是在获得锁之后,主动释放锁,进入等待一段时间,或者等待唤醒动作的发生。

    2. 结束(TERMINATED):已终止线程的线程状态,线程已经结束执行。

    补充:
    Java将操作系统中的运行和就绪两个状态合并称为运行状态。

    阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent包中Lock接口的线程状态却是等待状态,因为java.concurrent包中Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。

    线程状态概述

    2 线程状态转换

    上述6种状态在遇到特定事件发生的时候将会互相转换,它们的转换关系如下图:

    线程转换图

    上图状态的转换和方法已经很明朗了,下面重点说说几种状态转换,以及相关方法补充。

    2.1 进入等待/超时等待

    2.1.1 进入等待状态

    1. LockSupport.park()。
    2. 发生Io阻塞。
    3. suspend(),方法已过时。
    4. public final void wait() 释放锁
    5. public final void join() 释放锁

    2.1.1.1 wait方法的介绍

    wait方法属于object类,wait()方法使当前线程暂停执行并释放锁,让其他线程可以进入synchronized数据块,当前线程被放入对象等待队列中。Wait()方法必须被包含在对应的synchronized语句中,无论是wait()方法还是notify()方法都需要获取目标对象的一个监视器。

    当调用notify()方法后,将从对象的等待队列中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中线程才可能够获取锁标志;如果等待队列中没有线程,则notify()不起作用。notifyAll()则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。

    被唤醒的线程并不会立即执行而是尝试获得锁,执行唤醒方法的线程也并不会立即释放锁。

    2.1.1.2 join方法的介绍

    join方法在内部使用wait()方法进行等待,底层用wait()来实现,可以释放锁。join方法上加了synchronuzed关键字,因此使用wait没有问题。

    join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行,有些类似于同步的运行效果。在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。如果有多个线程,除了A线程之外的其他线程正常竞争cpu和锁。

    join方法中如果传入参数,则表示这样的意思:如果A线程中调用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。(其实join()中调用的是join(0))。主线程中调用join,则主线程等待, 其他多个线程之间并不需要互相等待。

    join()与synchronized的区别是:join在内部调用wait()方法进行等待,而synchronized关键字使用的是"对象监视器"原理作为同步。

        /**
         * join方法
         * @throws InterruptedException
         */
        public final void join() throws InterruptedException {
            //内部调用join(long millis)方法,参数为0 ,表示无限等待
            join(0);
        }
    
        /**
         * 等待millis毫秒
         * @param millis
         * @throws InterruptedException
         */
        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");
            }
            //millis等于0 表示无限期等待
            if (millis == 0) {
                while (isAlive()) {
                    //调用wait方法
                    wait(0);
                }
            } 
            //否则,限时等待
            else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    //调用wait方法
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }
    

    2.1.2 进入超时等待

    1. public final void join(long millis) --超时等待 释放锁
    2. LockSupport.parkNanos
    3. LockSupport.parkUntil
    4. wait(long timeout); --超时等待 释放锁
    5. public static void sleep(long millis); —超时等待 不释放锁

    2.1.2.1 sleep方法的介绍

    sleep方法使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。sleep会让其他所有线程都有同等的cpu争夺权力

    睡眠时被中断,则会在sleep()处抛出InterruptedException 异常。

    在调用Thread.sleep(long millis)时为millis 参数传递了一个负数, 则会抛出IllegalArgumentException 异常.

    2.1.2.2 LockSupport类简介

    LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,当然阻塞之后肯定得有唤醒的方法。

    常用方法:

    方法名称描述
    void park()阻塞当前线程,如果调用unpark(Thread)方法或被中断,才能从park()返回。
    void parkNanos(long nanos)阻塞当前线程,超时返回,阻塞时间最长不超过nanos纳秒。
    void parkUntil(long deadline)阻塞当前线程,直到deadline时间点
    void unpark(Thread)唤醒处于阻塞状态的线程

    park不需要获取某个对象的锁。因为中断的时候park不会抛出InterruptedException异常,所以需要在park之后自行判断中断状态,然后做额外的处理。

    2.1.2.3 过期的suspend和resume方法

    suspend方法被不推荐使用。不推荐使用suspend()去挂起线程的原因,是因为suspend()在导致线程暂停的同时,并不会去释放任何锁资源。其他线程都无法访问被它占用的锁。直到对应的线程执行resume()方法后,被挂起的线程才能继续,从而其它被阻塞在这个锁的线程才可以继续执行。如果resume()操作出现在suspend()之前执行,那么线程将一直处于挂起状态,同时一直占用锁,这就容易产生死锁。

    而且,对于被挂起的线程,它的线程状态居然还是RUNNABLE

            //创建子线程,在其内部调用suspend让其"阻塞"
            Thread thread = new Thread(() -> Thread.currentThread().suspend());
            thread.start();
            //主线程睡眠三秒,让子线程充分运行
            Thread.currentThread().sleep(3000);
            //获取子线程状态,发现还是RUNNABLE状态
            Thread.State state = thread.getState();
            System.out.println(state);
    

    2.4 进入RUNNABLE状态

    1. TIMED_WAITING状态结束
    2. WAITING状态被唤醒
    3. BLOCKED状态获得锁
    4. public static void yield();
    5. 线程的cpu时间片使用完毕还未执行完任务,重回就绪态,但此时不会释放锁。

    2.4.1 yield方法的介绍

    yield方法又称为“线程礼让”,使调用线程释放cpu执行权,让自己和其他多个线程重新争夺cpu执行权。

    线程直接回到RUNNABLE状态,而不是让线程处于阻塞态,因此也有可能是当前让步的线程又进入到“运行状态”继续运行

    yield会尽量让同等级和高等级的线程具有更大的争夺权,而sleep会让所有线程都有同等的争夺权力,但它们并不是绝对的。毕竟java线程最终是调用操作系统的资源生成的,充满了不确定性。

    yield方法不会释放持有已获得的锁,只是释放cpu的执行权

    如果有什么不懂或者需要交流,各位可以留言。另外,希望收藏、关注一下,我将不间断更新Java各种教程!

    展开全文
  • Java 线程6种状态(简单介绍)

    千次阅读 2018-08-15 08:19:50
    关于Java线程状态网上的说法不一,有的说是6种状态,有的说是5中状态,索性就查看了一下Java源码。Thread类里面有一个枚举类,如下: public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING,...
  • 线程的5种状态详解

    万次阅读 多人点赞 2018-08-23 11:02:42
    Java中的线程的生命周期大体可分为5种状态。 1.新建(NEW):新创建了一个线程对象。 2.可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态线程位于可运行线程池中,...
  • Java线程到底有几种状态

    千次阅读 2019-08-19 23:14:06
    前言 很多文章说Java线程有五状态:NEW(新建)、RUNNABLE(就绪)、RUNNING(运行)、BLOCKED(阻塞)...线程状态 Java线程到底有几状态,其实只要打开一下JDK源码,看一下java.lang.Thread类就知道了,java.l...
  • Java中线程状态分为6种。 1.初始(NEW):新创建了一个线程对象,但还没有调用start()方法。 2.运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,...
  • 简述线程的几种状态以及状态之间的转换

    千次阅读 多人点赞 2019-08-23 21:38:24
    线程有以下几种状态 1、new 新建状态(此时线程刚被new出来,还没执行start()方法) 2、Runable运行状态,有执行资格又有执行权,但它可能正在等待来自操作系统的其他资源,例如处理器。 3、Blocked 阻塞状态,也...
  • Java 线程的七种状态

    千次阅读 2019-09-26 19:31:10
    Java 线程状态转换图 Java 线程状态 在 Java 线程的生命周期中,按复杂的并发场景考虑,可将 Java 线程的状态分为七,分别是:新建(New),可运行(Runnable 或 Ready),运行(Running),无限期等待(Waiting...
  • java多线程的几种状态

    万次阅读 2018-09-04 13:00:38
    从Thread类的源码中可以看出线程一共有6种状态: 这六种状态分别是: 1. New:初始状态线程被创建,没有调用start() 2. Runnable:运行状态,Java线程把操作系统中的就绪和运行两种状态统一称为“运行中” 3. ...
  • 线程及线程池的五种状态

    千次阅读 多人点赞 2019-06-21 16:14:27
    线程的5种状态 线程可以有如下5种状态:New 、Runnable 、Running 、Blocked 、Dead 状态之间的转换如图: 1.New (新创建) 当用new操作符创建一个线程时,如new Thread®,该线程还没有开始运行。这意外这它的状态...
  • 线程5种状态及常见问题

    千次阅读 2017-10-19 18:22:05
    线程的5种状态:  每个 Java 程序都有一个缺省的主线程,对于 Java 应用程序,主线程是 main()方法执行的线索; 对于 Applet 程序,主线程是指挥浏览器加载并执行 Java Applet 程序的线索。要想...
  • Java线程6种状态

    千次阅读 2019-05-26 15:46:56
    Java的线程大致有6种状态: NEW: 新建状态,new了一个线程。 Runable: 可执行状态线程调用了start()或run()方法,或者等待结束,都会进入Runable状态,在操作系统或处理器而言,java的Runable状态可能是他们...
  • 线程的生命周期 ...Java 语言中线程共有六种状态。 NEW(初始化状态) RUNNABLE(可运行 / 运行状态) BLOCKED(阻塞状态) WAITING(无限时等待) TIMED_WAITING(有限时等待) TERMINATED(终止状态)...
  • 线程的几种状态转换

    千次阅读 2018-07-22 20:35:38
    线程一共有以下几种状态: 1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态线程位于“可运行线程池”中,变得可运行,只等待获取...
  • Python 线程的五种状态、守护线程

    千次阅读 2019-08-20 11:07:49
    一、线程的五种状态 大多数线程的生命周期经历有 新建、就绪、运行、阻塞、死亡 这五种状态,对于多线程来说,一个线程不可能始终霸占着CPU,CPU需要在不同线程之间切换,于是线程状态也会随之改变。 1.新建 当...
  • 线程一共有几种状态

    千次阅读 2019-02-19 14:43:44
    一、线程6状态: 1、New(初始) 2、Runnable 3、Blocked 4、Waiting 5、Time_waiting 6、Terminated 二、线程各种状态的切换 三、如何终止一个线程? 1:stop()-&gt;不建议使用,相当于kill -9 ...
  • 介绍Java8中Thread(线程)定义的6种状态,并和传统线程模型的三种/五种状态进行对比
  • 现在 Java 面试,基本上都会问到多线程,那么随之而来的线程状态,很多时候都会被问到,大部分人都知道线程的几状态,但是让你整体全部串起来,做到面试时游刃有余,估计很多人记忆不是很清晰。 今天武哥就把这些...
  • 一、线程的四种状态 新建(new):处于该状态的时间很短暂。已被分配了必须的系统资源,并执行了初始化。表示有资格获得CPU时间。调度器可以把该线程变为runnable或者blocked状态 就绪(Runnable):这种状态下...
  • 1,NEW()新建 线程刚被创建,但未被启动。也就是没有调用start方法。...当一个线程试图获取一个对象锁,而这对象锁被其他线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状...
  • Java线程线程的五种状态

    千次阅读 2016-10-11 14:17:48
    线程的 5 中状态 1. New 新建状态 当程序使用 new 关键字创建了一个线程后,该线程就处于新建状态,此时线程还未启劢, 当线程对象调用 start()方法时,线程启劢,迚入 Runnable 状态 2. Runnable 可运行(就绪...
  • Java的六种线程状态

    千次阅读 2021-09-09 09:19:22
    Java语言定义了6种线程状态,在任意一个时间点,一个线程只能有且只有其中的一种状态,这6种状态分别如下。 新建(New):创建后尚未启动的线程处于这种状态。 运行(Runable):Runable包括了操作系统线程状态...
  • 线程6种状态以及转变: java的线程一共6种状态。具体代码见: java.lang.Thread.State 1 NEW 新建状态 Thread state for a thread which has not yet started. 线程还没有调用start的时候 2 ...
  • 状态线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。 3.运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。 4.阻塞(BLOCKED):阻...
  • Java的六种线程状态(不是五

    千次阅读 2019-04-29 13:28:38
    网上的文章鱼龙混杂,对于Java到底几种线程状态?这个问题,根据《Java并发编程》这本经典的教材里提到的,是六状态,不是很多文章中提到的五状态。这些文章中所提到的是操作系统的五状态 Java线程的六状态...
  • Java线程的5种状态状态之间转换

    万次阅读 多人点赞 2017-06-26 16:18:23
    Java中的线程的生命周期大体可分为5种状态。 1. 新建(NEW):新创建了一个线程对象。 2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态线程位于可运行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,053,833
精华内容 421,533
关键字:

线程的6种状态