精华内容
下载资源
问答
  • Java多线程生命周期的讲解,很详细,希望能帮到大家
  • PAGE / NUMPAGES Java虚拟机管理类和对象的生命周期 1类的生命周期从类被加载连接初始化开始到类被卸载结束 2类处于生命周期时它的二进制数据位于运行时方法区内在堆区还有一个相应的描述类的Class类的对象个人收集...
  • | 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...为什么要了解线程生命周期? ...

    | 好看请赞,养成习惯

    • 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想

    • If you can NOT explain it simply, you do NOT understand it well enough

    现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star🌟

    为什么要了解线程的生命周期?

    之前写过 Spring Bean 生命周期三部曲:

    1. Spring Bean生命周期之缘起
    2. Spring Bean生命周期之缘尽
    3. Spring Aware 到底是什么?

    有朋友留言说:“了解了它们的生命周期后,使用 Spring Bean 好比看到它们的行动轨迹,现在使用就一点都不慌了”。我和他一样,了解事物的生命周期目的很简单,唯【不慌】也

    Java 并发系列 已经写了很多,从来还没提起过那个它【Java线程生命周期】。有了前序理论图文的铺垫,在走进源码世界之前,谈论它的时机恰好到了。因为,编写并发程序的核心之一就是正确的摆弄线程状态

    线程生命周期的几种状态

    刚接触线程生命周期时,我总是记不住,也理解不了他们的状态,可以说是比较混乱,更别说它们之间是如何进行状态转换的了。原因是我把操作系统通用线程状态编程语言封装后的线程状态 概念混淆在一起了

    操作系统通用线程状态

    个人觉得通用线程状态更符合我们的思考习惯。其状态总共有 5 种 (如下图)。对于经常写并发程序的同学来说,其嘴里经常念的都是操作系统中的这些通用线程状态,且看

    除去生【初始状态】死【终止状态】,其实只是三种状态的各种转换,听到这句话是不是心情放松了很多呢?

    为了更好的说明通用线程状态Java 语言中的线程状态,这里还是先对前者进行简短的说明

    初始状态

    线程已被创建,但是还不被允许分配CPU执行。注意,这个被创建其实是属于编程语言层面的,实际在操作系统里,真正的线程还没被创建, 比如 Java 语言中的 new Thread()。

    可运行状态

    线程可以分配CPU执行,这时,操作系统中线程已经被创建成功了

    运行状态

    操作系统会为处在可运行状态的线程分配CPU时间片,被 CPU 临幸后,处在可运行状态的线程就会变为运行状态

    休眠状态

    如果处在运行状态的线程调用某个阻塞的API等待某个事件条件可用,那么线程就会转换到休眠状态,注意:此时线程会释放CPU使用权,休眠的线程永远没有机会获得CPU使用权,只有当等待事件出现后,线程会从休眠状态转换到可运行状态

    终止状态

    线程执行完或者出现异常 (被interrupt那种不算的哈,后续会说)就会进入终止状态,正式走到生命的尽头,没有起死回生的机会

    接下来就来看看你熟悉又陌生,面试又经常被问到的Java 线程生命周期吧

    Java语言线程状态

    在 Thread 的源码中,定义了一个枚举类 State,里面清晰明了的写了Java语言中线程的6种状态:

    1. NEW
    2. RUNNABLE
    3. BLOCKED
    4. WAITING
    5. TIMED_WAITING
    6. TERMINATED

    这里要做一个小调查了,你有查看过这个类和读过其注释说明吗?(欢迎留言脚印哦)

    耳边响起五环之歌,Java中线程状态竟然比通用线程状态的 5 种多1种,变成了 6 种。这个看似复杂,其实并不是你想的那样,Java在通用线程状态的基础上,有裁剪,也有丰富,整体来说是少一种。再来看个图,注意颜色区分哦

    Java 语言中

    • 将通用线程状态的可运行状态运行状态合并为 Runnable
    • 休眠状态细分为三种 (BLOCKED/WAITING/TIMED_WAITING); 反过来理解这句话,就是这三种状态在操作系统的眼中都是休眠状态,同样不会获得CPU使用权

    看上图右侧【Java语言中的线程状态】,进一步简洁的说,除去线程生死,我们只要玩转 RUNNABLE休眠状态的转换就可以了,编写并发程序也多数是这两种状态的转换。所以我们需要了解,有哪些时机,会触发这些状态转换

    远看看轮廓, 近看看细节。我们将上面Java语言中的图进行细化,将触发的节点放到图中 (这看似复杂的图,其实三句话就能分解的,所以别慌),且看:

    RUNNABLE与BLOCKED状态转换

    当且仅有(just only)一种情况会从 RUNNABLE 状态进入到 BLOCKED 状态,就是线程在等待 synchronized 内置隐式锁;如果等待的线程获取到了 synchronized 内置隐式锁,也就会从 BLOCKED 状态变为 RUNNABLE 状态了

    注意:

    上面提到,以操作系统通用状态来看,线程调用阻塞式 API,会变为休眠状态(释放CPU使用权),但在JVM层面,Java线程状态不会发生变化,也就是说Java线程的状态依旧会保持在 RUNNABLE 状态。JVM并不关心操作系统调度的状态。在JVM看来,等待CPU使用权(操作系统里是处在可执行状态)与等待I/O(操作系统是处在休眠状态),都是等待某个资源,所以都归入了RUNNABLE 状态

    ​ —— 摘自《Java并发编程实战》

    RUNNABLE与WAITING状态转换

    调用不带时间参数的等待API,就会从RUNNABLE状态进入到WAITING状态;当被唤醒就会从WAITING进入RUNNABLE状态

    RUNNABLE与 TIMED-WAITING 状态转换

    调用带时间参数的等待API,自然就从 RUNNABLE 状态进入 TIMED-WAITING 状态;当被唤醒或超时时间到就会从TIMED_WAITING进入RUNNABLE状态

    看图中的转换 API 挺多的,其实不用担心,后续分析源码章节,自然就会记住的,现在有个印象以及知道状态转换的节点就好了


    相信到这里,你看Java线程生命周期的眼神就没那么迷惑了,重点就是RUNNABLE与休眠状态的切换,接下来我们看一看,如何查看线程中的状态,以及具体的代码触发点

    如何查看线程处在什么状态

    程序中调用 getState() 方法

    Thread 类中同样存在 getState() 方法用于查看当前线程状态,该方法就是返回上面提到的枚举类 State

    NEW

    就是上面提到, 编程语言中特有的,通过继承 Thread 或实现 Runnable 接口定义线程后,这时的状态都是 NEW

    Thread thread = new Thread(() -> {});
    System.out.println(thread.getState());

    RUNNABLE

    调用了 start() 方法之后,线程就处在 RUNNABLE 状态了

    Thread thread = new Thread(() -> {});
    thread.start();
    //Thread.sleep(1000);
    System.out.println(thread.getState());

    BLOCKED

    等待 synchronized 内置锁,就会处在 BLOCKED 状态

    public class ThreadStateTest {
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(new DemoThreadB());
            Thread t2 = new Thread(new DemoThreadB());
    
            t1.start();
            t2.start();
    
            Thread.sleep(1000);
    
            System.out.println((t2.getState()));
            System.exit(0);
        }
    }
    
    class DemoThreadB implements Runnable {
        @Override
        public void run() {
            commonResource();
        }
    
        public static synchronized void commonResource() {
            while(true) {
    
            }
        }
    }

    WAITING

    调用线程的 join() 等方法,从 RUNNABLE 变为 WAITING 状态

    public static void main(String[] args) throws InterruptedException {
            Thread main = Thread.currentThread();
    
            Thread thread2 = new Thread(() -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
                System.out.println(main.getState());
            });
            thread2.start();
            thread2.join();
        }

    TIMED-WAITING

    调用了 sleep(long) 等方法,线程从 RUNNABLE 变为 TIMED-WAITING 状态

    public static void main(String[] args) throws InterruptedException {
            Thread thread3 = new Thread(() -> {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
            // 为什么要调用interrupt方法?
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
            });
            thread3.start();
    
            Thread.sleep(1000);
            System.out.println(thread3.getState());
        }

    TERMINATED

    线程执行完自然就到了 TERMINATED 状态了

    Thread thread = new Thread(() -> {});
    thread.start();
    Thread.sleep(1000);
    System.out.println(thread.getState());

    以上是程序中查看线程,自己写写测试看看状态还好,现实中的程序怎么可能允许你加这么多无用代码,所以,翠花,上酸菜(jstack

    jstack 命令查看

    相信你听说过这玩意,jstack 命令就比较强大了,不仅能查看线程当前状态,还能看调用栈,锁等线程栈信息

    大家可以随意写一些程序,这里我用了上面 WAITING 状态的代码, 修改睡眠时间 Thread.sleep(100000),然后在终端按照下图标示依次执行下图命令

    更多功能还请大家自行查看,后续会单独写文章来教大家如何使用jstack查看线程栈信息

    Arthas

    这个利器,无须多言吧,线上找茬监控没毛病,希望你可以灵活使用这个工具,攻克疑难杂症

    查看线程栈详细信息,非常方便:https://alibaba.github.io/arthas/thread.html

    相信你已经和Arthas确认了眼神

    关于线程生命周期状态整体就算说完了,编写并发程序时多问一问自己:

    调用某个API会将你的线程置为甚么状态?

    多问自己几次,自然就记住上面的图了

    灵魂追问

    1. 为什么调用 Thread.sleep, catch异常后,调用了Thread.currentThread().interrupt();

    2. 进入 BLOCKED只有一种情况,就是等待 synchronized 监视器锁,那调用 JUC 中的 Lock.lock() 方法,如果某个线程等待这个锁,这个线程状态是什么呢?为什么?

      public class ThreadStateTest {
      
          public static void main(String[] args) throws InterruptedException {
              TestLock testLock = new TestLock();
      
              Thread thread2 = new Thread(() -> {
                  testLock.myTestLock();
              }, "thread2");
      
              Thread thread1 = new Thread(() -> {
                      testLock.myTestLock();
                  }, "thread1");
      
              thread1.start();
              Thread.sleep(1000);
      
              thread2.start();
              Thread.sleep(1000);
      
              System.out.println("****" + (thread2.getState()));
      
              Thread.sleep(20000);
          }
      }
      
      @Slf4j
      class TestLock{
          private final Lock lock = new ReentrantLock();
      
          public void myTestLock(){
              lock.lock();
              try{
                  Thread.sleep(10000);
                  log.info("testLock status");
              } catch (InterruptedException e) {
                  log.error(e.getMessage());
              } finally {
                  lock.unlock();
              }
          }
      }
    1. synchronized 和 Lock 有什么区别?

    参考

    感谢前辈们总结的精华,自己所写的并发系列好多都参考了以下资料

    • Java 并发编程实战
    • Java 并发编程之美
    • 码出高效
    • Java 并发编程的艺术
    • ......

    我这面也在逐步总结常见的并发面试问题(总结ing......)答案整理好后会通知大家,请持续关注

    展开全文
  • 线程生命周期(状态)

    千次阅读 2020-06-26 14:49:35
    线程生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞 (Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自 运行,所以CPU需要在多条线程之间切换,...

    当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。 在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞 (Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自 运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换 。

    )

    1.新建状态(NEW)

    当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配 内存,并初始化其成员变量的值 。

    2.就绪状态(RUNNABLE)

    当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和 程序计数器,等待调度运行。

    3.运行状态(RUNNING)

    如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。

    4.阻塞状态(BLOCKED)

    阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。 直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状 态。阻塞的情况分三种:

    (1)等待阻塞 ( o.wait-> 等待对列 )

    运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue) 中。

    (2)同步阻塞 (lock-> 锁池 )

    运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线 程放入锁池(lock pool)中。

    (3)其他阻塞 (sleep/join)

    运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时, JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O 处理完毕时,线程重新转入可运行(runnable)状态。

    5.线程死亡(DEAD)

    线程会以下面三种方式结束,结束后就是死亡状态。

    • 正常结束: run()或call()方法执行完成,线程正常结束。
    • 异常结束: 线程抛出一个未捕获的Exception或Error。
    • 调用 stop: 直接调用该线程的stop()方法来结束该线程— 该方法通常容易导致死锁,不推荐使用。
    展开全文
  • 线程生命周期.pdf

    2020-03-17 18:05:17
    以图表形式详细列出java线程生命周期,创建线程,线程就绪,线程阻塞,线程中断,线程唤醒,线程运行之间的关系
  • Java线程生命周期及五种基本状态

    千次阅读 多人点赞 2020-02-06 20:11:39
    一、Java中线程生命周期图 用这张图可以概述大多的线程创建及运行,简单易懂的掌握线程知识!!! 二、线程的五种基本状态 新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动。如:Thread t = ...

    一、Java中线程生命周期图

    用这张图可以概述大多的线程创建及运行,简单易懂的掌握线程知识!!!
    在这里插入图片描述

    二、线程的五种基本状态

    新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动。如:Thread t = new MyThread();

    就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

    运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

    阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

    1)等待阻塞—位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。

    2)同步阻塞 --位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。【线程在获取synchronized同步锁失败(因为锁被其它线程所占用)】

    3)其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    展开全文
  • 线程生命周期.png

    2019-09-17 13:47:07
    线程生命周期图解,一分钟了解线程从生到死全过程,图文并茂,通俗易懂,容易记忆。独家原创。欢迎下载。
  • 1. 线程生命周期 线程生命周期图 新建状态(New) 当线程对象创建后,即进入新建状态,如:Thread t = new MyThread(); 就绪状态(Runnable) 当调用线程对象的start()方法时,线程即进入就绪状态。处于就绪...

    1. 线程生命周期

    线程生命周期图
    java线程的五种基本状态

    • 新建状态(New)
      当线程对象创建后,即进入新建状态,如:Thread t = new MyThread();

    • 就绪状态(Runnable)
      当调用线程对象的start()方法时,线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好准备,随时等待CPU调度执行,并不是说执行了start()方法就立即执行。

    • 运行状态(Running)
      当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。

    • 阻塞状态(Blocked)
      处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。

    • 死亡状态
      线程执行完毕或者是异常退出,该线程结束生命周期。

    阻塞状态分类

    • 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    • 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程占用),它会进入到同步阻塞状态;
    • 其他阻塞:通过调用线程的sleep()或join()或发出I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    2. 线程状态控制

    • 线程休眠-sleep()
      sleep()会让当前的线程暂停一段时间,并进入阻塞状态,调用sleep并不会释放锁。

    注意点:

    1. sleep()是静态方法,故不要用线程实例对象调用它,它睡眠的始终是当前正在运行的线程,而不是调用它的线程对象。
    2. 线程实际休眠时间会大于设定的时间。
    3. sleep()方法声明抛出InterruptedException,所以调用sleep()需要捕获异常。
    • 线程让步-yield()
      调用yield()方法之后,从运行状态转换到就绪状态,CPU从就绪状态队列中只会选择与该线程优先级相同或者是优先级更高的线程去执行。

      yield()方法不需要抛出异常。

    • 线程合并-join()
      线程合并就是将几个并发线程合并为一个单一线程执行,应用场景就是当一个线程的执行必须是要等到其他线程执行完毕之后才能执行。

    • 线程优先级设置-priority
      Thread类提供setPriority(int newPriority)和getPriority()方法设置和返回优先级。

    • 守护线程-Daemon
      守护线程是为其他非守护线程提供服务的,比如JVM中的垃圾回收线程就是守护线程。当所有的前台线程都进入死亡状态时,守护线程会自动死亡。

      调用Thead实例的setDaemon(true)方法可以将指定的线程设置为守护线程。

    3. 线程创建方式

    1.通过继承Thread类来创建并启动多线程的方式。
    Java所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建并启动多线程的步骤如下:

    1. 定义Thread类的子类,并重写该类的run()方法,run()方法即称为线程执行体。
    2. 创建Thread子类的实例。
    3. 调用线程对象的start()方法来启动该线程。

    继承Thread类创建线程示例

    public class MyThreadTest extends Thread {
        private int i;
    
        @Override
        public void run(){
            for (; i < 100; i++) {
                System.out.println(this.getName() + " " + i);
            }
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                // 调用Thread的currentThread方法获取当前线程
                System.out.println(Thread.currentThread().getName() + " " + i);
                if (i == 20) {
                    // 创建、并启动第一条线程
                    new MyThreadTest().start();
                    // 创建、并启动第二条线程
                    new MyThreadTest().start();
                }
            }
        }
    }
    

    2.通过实现Runnable接口来创建并启动线程的方式。
    实现Runnable接口创建线程步骤如下:

    1. 定义Runnable接口的实现类,并重写该接口的run()方法。
    2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
    3. 调用线程对象的start()方法来启动线程。

    需要注意的是:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。

    实现Runnable接口创建线程示例

    public class MyRunnableTest implements Runnable {
        private int i;
    
        void print() {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    
        @Override
        public void run() {
            for (; i < 100; i++) {
                print();
            }
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
                if (i == 20) {
                    MyRunnableTest st = new MyRunnableTest();
                    // 通过new Thread(target, name)方法创建新线程
                    // new Thread(st).start();亦可
                    new Thread(st, "新线程-1").start();
                    new Thread(st, "新线程-2").start();
                }
            }
        }
    }
    

    部分运行结果:
    部分运行结果

    从该运行结果中我们可以看出,控制台上输出的内容是乱序的,而且每次结果不尽相同。这是因为:

    1. 在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程共享同一个target,所以多个线程共享同一个线程类即线程的target类的实例属性。
    2. print()方法并不是线程安全的。

    解决方案:对print()方法添加synchronized关键字保证线程安全。

    synchronized void print() {
        System.out.println(Thread.currentThread().getName() + " " + i);
    }
    

    3.通过实现Callable接口来创建并启动线程的方式。
    从Java 5开始,Java提供了Callable接口,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大。

    • call()方法可以有返回值;
    • call()方法可以声明抛出异常。

    Java 5提供了Future接口来代表Callable接口call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口和Runnable接口可以作为Thread类的target。
    注意Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法返回值类型相同。

    创建并启动有返回值的线程的步骤如下:

    1. 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。
    2. 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了call()方法的返回值。
    3. 使用FutureTask对象作为Thread对象的target创建并启动新线程。
    4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

    注意:get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。另外FutureTask还提供了get(long timeout, TimeUnit unit)方法,如果在指定时间内,还没获取到结果,就直接返回null。

    实现Callable接口创建线程示例

    public class MyCallableTest implements Callable<Integer> {
    
        @Override
        public Integer call() throws Exception {
            int i = 0;
            for (; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
            return i;
        }
    
        public static void main(String[] args) {
            // 创建Callable对象
            MyCallableTest myCallableTest = new MyCallableTest();
            // 使用FutureTask来包装Callable对象
            FutureTask<Integer> task = new FutureTask<Integer>(myCallableTest);
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
                if (i == 20) {
                    // 实质还是以Callable对象来创建、并启动线程
                    new Thread(task, "callable").start();
                }
            }
            try {
                System.out.println("callable返回值:" + task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    总结:三种方式创建线程,继承Thread类,实现Runnable接口和实现Callable接口。实现Runnable接口和实现Callable接口的方式多个线程可以共享一个target对象,比较适用多个相同线程处理同一份资源的情况。

    展开全文
  • 线程生命周期 线程可分为五种状态,创建、就绪、运行、阻塞、死亡这五个状态。 创建状态 这个没有什么需要描述的,就是创建(new )一个新的线程对象 就绪状态 线程对象创建后、调用对象的start()方法,该线程将会...
  • GaiaThreadNest 用于线程生命周期控制的多线程应用程序框架。
  • 线程生命周期图 话不多说,直接上图 对于java线程的声明周期,很多人都说有ready(就绪)状态,其实对于java来说,就绪和运行中是统称为运行态的.
  • Java线程生命周期各个状态总结

    千次阅读 2017-11-12 22:24:22
    最近在学习Java技术相关基础知识,准备边学习便总结,写这个博客主要是做个记录方便自己回查,但然顺便也就方便了别人,这个作为Java...1、生命状态分类根据Java API文档将Java线程运行在JVM中的状态分成六个状态,废话
  • Java线程生命周期.zip

    2020-03-18 14:50:46
    Java线程生命周期
  • 主要介绍了Java 线程生命周期的相关资料,并附简单实例代码,帮助大家理解,需要的朋友可以参考下
  • 图解线程生命周期

    千次阅读 2020-08-10 19:41:50
    线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程生命周期中, 有几种状态呢?在API中 java.lang.Thread.State 这个枚举中给出了六种线程状态:
  • 主要介绍了Java 线程生命周期,结合完整实例形式分析了java线程周期相关的加锁、释放锁、阻塞、同步等原理与操作技巧,需要的朋友可以参考下
  • Java线程生命周期与状态切换

    千次阅读 2020-08-05 10:54:55
    前提最近有点懒散,没什么比较有深度的产出。刚好想重新研读一下JUC线程池的源码实现,在此之前先深入了解一下Java中的线程实现,包括线程生命周期、状态切换以及线程的上下文切换等等。编写...
  • 线程生命周期,把图转化为文字就是: 线程通过new方法创建,调用start()方法,线程进入就绪状态,等待系统的调度(时间片轮转调度)。当系统调度,进入运行状态。正常结束或者异常退出,进程进入死亡状态。处于...
  • 工程师培训资料;本章学习目标;线程生命周期;范例停止线程运行;谢谢大家的时间
  • 线程生命周期流程图

    2013-06-09 00:26:28
    我根据自己的理解画的这个线程生命流程图,希望对你们有点点的帮助吧!!!
  • 线程生命周期状态转化图
  • Java线程生命周期以及方法详解

    千次阅读 2019-06-24 16:25:43
    在进程中操作系统调度的最小单元是线程, 也叫轻量级进程(Light Weight Process) , 在一个进程里可以创建多个线程, 这些线程都拥有各自的计数器、 堆栈和局部变量等属性, 并且能够访问共享的内存变量。...
  • 线程生命周期

    千次阅读 2012-11-01 16:37:00
    线程生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5中状态。  当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他Java对象...
  • C++11线程生命周期

    千次阅读 2018-07-10 00:29:54
    线程也一样,父线程对子线程生命周期有很大的影响。 以下程序启动一个显示其ID的线程。 // threadForgetJoin.cpp #include &lt;iostream&gt; #include &lt;thread&gt; int main() { std::...
  • 线程生命周期及其状态转换 每个线程都有一个生命周期,它是由若干个不同的状态组成的。 一个线程在任何时候都处于某种线程状态。这些状态包括出生、 就绪、运行等待、休眠、阻塞、和死亡 (1)出生:线程被创建 (2)...
  • Java多线程(二)、线程生命周期和状态控制
  • 进程和多线程生命周期

    千次阅读 2020-02-28 12:34:59
    进程和线程 进程 对于操作系统来说,一个任务就是一个进程(Process)。 课本概念:程序的一个执行实例,正在执行的程序等。 内核观点:担当分配系统资源(CPU时间,内存)的实体 所以最后得出: 进程是担当分配系统...
  • 主要是线程基本概念,线程同步。线程生命周期。做了一个demo。
  • 简述线程生命周期

    2020-09-03 21:30:12
    线程生命周期包含5个阶段,包括新建,就绪,运行,阻塞,销毁。 新建:就是使用new方法,new出来的线程; 就绪:调用的线程的start()方法后,线程处于等待CPU分配资源阶段,谁先抢到CPU资源,谁开始执行; 运行:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 280,641
精华内容 112,256
关键字:

线程的生命周期