前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【多线程】线程状态和创建方式

【多线程】线程状态和创建方式

作者头像
沁溪源
发布于 2021-03-22 02:27:50
发布于 2021-03-22 02:27:50
42100
代码可运行
举报
文章被收录于专栏:沁溪源沁溪源
运行总次数:0
代码可运行

线程状态

线程共存在5种状态:新建、就绪、运行、阻塞、死亡,如下图:

解释说明各个状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、新建状态(New):新创建一个线程对象;
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()的方法。
    该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权;
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码;
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃了CPU的使用权,暂时停止运行;
    直到线程进入就绪状态,才有机会转到运行状态;
    4.1:等待阻塞:运行状态的线程执行wait()方法,JVM会把该线程放入等待池中;(wait会释放持有的锁);
    4.2:同步阻塞:运行状态的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中;
    4.3:其他阻塞:运行状态的线程执行sleep()或者join()方法,或者发出I/O请求时,JVM会把该线程置为阻塞状态;
    当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(sleep不会释放持有锁) 
5、死亡状态(Dead):线程执行完了或者因异常退出run()方法,该线程结束生命周期;  

线程创建方式

线程创建方式主要存在四种:

  • 1.继承Thread类;
  • 2.实现Runnable接口;
  • 3.使用Callable接口和Future接口;
  • 4.使用线程池创建线程,例如Executor;

继承Thread和实现Runnable接口创建线程方式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Task {

    /**
     * 实现Runnable接口实现线程
     */
    public static class TaskRunnable implements Runnable {
        private int i = 1;
        @Override
        public void run() {
            System.out.println("taskRunnable线程运行: " + i);
            i ++;
        }
    }

    /**
     * 继承Thread类实现线程
     */
    public static class TaskThread extends Thread {
        private int i = 1;
        @Override
        public void run() {
            System.out.println("taskThread线程运行: " + i);
            i ++;
        }
    }

    public static void main(String[] args) {

        System.out.println("=========Runnable======");
        Runnable r1 = new TaskRunnable();
        Thread threadRunnable1 = new Thread(r1);
//        threadRunnable1.start();
        //run()如果不开启线程,就是相当于普通方法,按照顺序执行,只有主线程一个(main线程)
        threadRunnable1.run();

        //1、创建线程
        Runnable r2 = new TaskRunnable();
        Thread threadRunnable2 = new Thread(r2);
        //2、调用start()方法:线程为就绪态,并且会自动调用run方法,所以不需要再次单独调用该方法
        threadRunnable2.start();
//        threadRunnable2.run();
        System.out.println("=========Thread========");
        TaskThread taskThread1 = new TaskThread();
//        taskThread1.start();
        taskThread1.run();

        TaskThread taskThread2 = new TaskThread();
        taskThread2.start();
        taskThread2.run();
    }
}

以上demo分别采用方式一和方式二创建线程,并重写run()方法,执行线程任务,关于这里涉及一道面试题start()和run()方法的区别,有兴趣的小伙伴们可以先思考一下,文章尾部会为大家揭秘。

Callable接口创建线程

这种方式相对于以上两种理解起来比较麻烦一点,进入正题之前,先带着大家了解CallableFutureTask接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@FunctionalInterface
public interface Callable<V> {
    /**
     * 线程执行体方法,相对于Runnable接口,Callable接口允许存在返回值,并抛异常
     */
    V call() throws Exception;
}

Future接口//
public interface Future<V> {

    /**
     * 尝试取消线程任务;
     *参数表示,是否终止正在执行的线程任务
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
    *如果线程任务在正常完成之前,被取消,则返回true;
    *Returns true if this task was cancelled before it completed normally.
     */
    boolean isCancelled();

    /**
    *线程任务完成,则返回true
    *完成情况包含:正常结束,异常退出,终止等等,都会返回true
    *
     */
    boolean isDone();

    /**
    *获取线程执行结果,调用此方法,主线程会被阻塞,直到子线程执行结束,返回执行结果
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 在一定时间内,获取子线程执行结果,否则超时,则获取结果失败,经过指定时间没有返回抛出TimeoutException
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

伪代码逻辑: 1.需要创建Callable子类对象,创建FutureTask对象,复写call(相当于run)方法,将其传递给FutureTask对象(相当于一个Runnable)。 2.创建Thread类对象,将FutureTask对象传递给Thread对象,调用start方法开启线程。 这种方式可以获得线程执行完之后的返回值。该方法使用Runnable功能更加强大的一个子类.这个子类是具有返回值类型的任务方法。 简单看一个demo理解上面的伪代码逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            sum = sum + i;
        }
        return sum;
    }
}

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
//        将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
//        将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread,并调用start()
        new Thread(futureTask).start();
        Integer sum = futureTask.get();
        System.out.println(sum);
    }

线程池创建线程

Thread 类中的 start() 和 run() 方法有什么区别? 调用 start() 方法才会启动新线程;如果直接调用 Thread 的 run() 方法,它的行为就会和普通的方法一样;为了在新的线程中执行我们的代码,必须使用 Thread.start() 方法。

1) start:   用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。 通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法, 这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。 2) run:   run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。 总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。 这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/02/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
01.线程状态/创建/启动
多线程作为Java中很重要的一个知识点,在此还是有必要总结一下的。 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程
Java帮帮
2018/03/15
7870
01.线程状态/创建/启动
【Java】多线程初探
 参考书籍:《Java核心技术 卷Ⅰ 》 Java的线程状态 从操作系统的角度看,线程有5种状态:创建, 就绪, 运行, 阻塞, 终止(结束)。如下图所示 而Java定义的线程状态有: 创建(New)
啦啦啦321
2018/03/30
7260
【Java】多线程初探
Java多线程与并发
答:进程是资源分配的最小单位,线程是CPU调度的最小单位。   1)、进程是资源分配的基本单位,所有与进行相关的资源,都被记录在进程控制块PCB中,以表示该进程拥有这些资源或者正在使用它们。   2)、进程是抢占处理机的调度单位,线程属于某个进程,共享其资源。进程拥有一个完整的虚拟内存地址空间,当进程发生调度的时候,不同的进程拥有不同的虚拟地址空间,而同一进程内不同线程共享同一地址空间,与进程相对应。线程与资源分配无关,它属于某一个进程,并与进程内的其它线程一起共享进程里面的资源。   3)、线程只由堆栈、寄存器、程序计数器和线程计数表TCB组成。
别先生
2020/04/10
1.1K0
Java多线程与并发
一篇文章弄懂Java多线程基础和Java内存模型
写在前面:提起多线程大部门同学可能都会皱起眉头不知道多线程到底是什么、什么时候可以用到、用的时候是不是有共享变量问题等等一大堆问题。本篇文章将分为两部分第一部分是讲解多线程基础、第二部分讲解Java内存模型。
全栈程序员站长
2022/08/31
2550
一篇文章弄懂Java多线程基础和Java内存模型
Java 多线程系列Ⅰ
首先,所有的创建线程的方式都是基于Thread类来实现,每个线程都必须通过 Thread 类的构造方法创建,并实现 run() 方法来执行线程的任务。
终有救赎
2023/12/26
2010
Java 多线程系列Ⅰ
多线程基础知识(全面):创建线程、线程状态如何变化、wait()、notify()、sleep()、停止线程
一直想着抽时间 学习多线程相关知识,目前整理了多线程的基础部分,特在此记录下,并发安全、线程池等后续再补充。
寻求出路的程序媛
2024/05/01
2720
多线程基础知识(全面):创建线程、线程状态如何变化、wait()、notify()、sleep()、停止线程
java基础第十六篇之多线程
1:线程的概念 进程(任务):一个正在运行的程序 进程的调度:CPU来决定什么时候该运行哪个进程 (时间片轮流法) 线程在一个应用程序中,同时,有多个不同的执行路径,是进程中的实际运作单位。 好处是提高程序效率。
海仔
2019/08/05
2950
Java多线程
例如打开你的计算机上的任务管理器,会显示出当前机器的所有进程,QQ,Chrome等,当QQ运行时,就有很多子任务在同时运行。比如,当你边打字发送表情,边好友视频时这些不同的功能都可以同时运行,其中每一项任务都可以理解成“线程”在工作。
用户10358987
2024/04/23
1210
Java多线程
Java 多线程
程序(program)是为完成特定任务、用某种语言编写的一组指令的集合 即指一 段静态的代码,静态对象。
Java_慈祥
2024/08/06
1210
Java 多线程
Java多线程一:基础知识与线程创建的几种方式
进程是系统资源分配的基本单位,线程是CPU调度的基本单位,一个进程可以包含多个线程,同一个进程下面的资源共享很容易,但是进程之间的资源共享相对较难。
全栈学习笔记
2022/04/24
2460
【Java】创建多线程的四种方式
每个线程都有一定的优先级,同优先级线程组成先进先出队列(先到先服务),使用分时调度策略。优先级高的线程采用抢占式策略,获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。
CODER-V
2023/03/04
1.4K0
【Java】创建多线程的四种方式
Java进程和线程
1. 进程和线程 进程:进程表示一个运行的程序,程序的代码段,数据段这些都是存放在磁盘中的,在运行时加载到内存中。
翎野君
2023/05/12
7420
Java进程和线程
多线程详解(一)
线程首先得说到进程, 进程:正在执行的应用程序。是系统进行资源分配和调用的独立单元。每一个进程都有他自己的内存空间和系统资源,简单说就是程序进入内存运行变成一个进程,具有一定独立功能。 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。
smallmayi
2022/05/12
2130
☀️苏州程序大白一文解析Java多线程☀️《❤️记得收藏❤️》
程序:是为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象。
苏州程序大白
2021/10/13
3650
Java多线程与并发
进程是资源分配的基本单位,所有与进程有关的资源都记录在进程控制块PCB中,以表示进程拥有这些资源或者正在使用它们,进程也是抢占处理机的调度单位,它拥有完整的虚拟内存地址空间,当进程发生调度时,不同的进程拥有不同的地址空间,而同一进程内的不同线程共享同一地址空间。与进程相对应,线程与资源分配无关,它属于某一个进程,并与进程内的其它线程共享进程的资源。
ha_lydms
2023/08/10
2250
Java多线程与并发
1.11 手把手教你从多线程到线程池
单CPU系统中: 每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。 多CPU系统中: 则这些可以并发执行的程序便可以分配到多个处理器上(CPU),实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序。
ha_lydms
2023/08/09
2500
1.11 手把手教你从多线程到线程池
夯实Java基础系列17:一文搞懂Java多线程使用方式、实现原理以及常见面试题
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
Java技术江湖
2019/10/08
1.2K0
【多线程实践】一、为何使用多线程&三种线程创建方式利弊分析
在平常的业务场景中,多线程无疑是比较常用的,而且熟练的使用多线程是开发高并发系统的基础,今天呢,我们就来根据在实际开发中是如何使用多线程的来探讨一下多线程的相关技术,少讲理论多谈实践,以实际开发的角度去总结一下。
灰小猿
2022/10/08
4810
【多线程实践】一、为何使用多线程&三种线程创建方式利弊分析
Java多线程详解
每个运行的程序就是一个进程,当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个进程。
二十三年蝉
2018/08/01
8841
Java多线程详解
java 多线程
就绪,当线程调用了strat()方法的时候,线程就绪,会为其创建方法调用栈和程序计数器。
mySoul
2018/11/19
7930
相关推荐
01.线程状态/创建/启动
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档