Java实现多线程有几种方式(满分回答)

news2025/7/8 5:56:25

目录

    • JDK8 创建的线程的两种方式
      • orcle文档解释
      • 方式一:继承Thread类
      • 方式二:实现Runnable接口
      • 同时用两种的情况
    • 其他间接创建方式
      • Callable接口
      • 线程池

JDK8 创建的线程的两种方式

orcle文档解释

orcle文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html

image-20230222102145410

总结:

准确的讲,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式:

  • 方法一:实现Runnable接口的重写run方法,并把Runnable实例传给Thread类
  • 方法二∶重写Threadrun方法(继承Thread类)

(其他一些方式,究其根本都是间接的通过上面两种方式创建的)

方式一:继承Thread类

public static void main(String[] args) {
        System.out.println("主线程运行:" + Thread.currentThread().getName());
        Task1 task = new Task1();
        task.start();
    }

    static class Task1 extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("task1线程运行" + Thread.currentThread().getName());
                System.out.println("Task11继承Thread实现多线程");
            }
        }
    }

}
  • 自定义线程类继承Thread类

  • 重写run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

方式二:实现Runnable接口

public static void main(String[] args) {
        Task task = new Task();
        Thread thread  = new Thread(task);
        thread.start();
    }

    static class Task implements Runnable{

        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println("task1线程运行" + Thread.currentThread().getName());
                System.out.println("Task11实现Runnable接口实现多线程");
            }
        }
    }
  • 定义MyRunnable类实现Runnable接口

  • 实现run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

同时用两种的情况

public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("实现Runnable的run方法");
        }
    }){
        @Override
        public void run() {
            System.out.println("匿名内部类,重写Thread类的run方法");
        }
    }.run();
}

结果:

匿名内部类,重写Thread类的run方法

分析:

这里使用的匿名内部类,在匿名内部类里面又重写了Thread类的run方法。创建Thread类的同时传入了Runnable对象,这时候Thread类的run已被重写,不再是原生方法的逻辑:执行传入task的run

image-20230211121531177

所以即便传入Runnable,也不会被执行。

其他间接创建方式

Callable接口

public static void main(String[] args) {
    Task task = new Task();
    FutureTask<Integer> ft = new FutureTask<>(task);
    Thread thread = new Thread(ft);
    thread.start();

}

static class Task implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        for (int i = 0; i < 20; i++) {
            System.out.println("task1线程运行" + Thread.currentThread().getName());
            System.out.println("Task11实现Callable接口实现多线程");
        }
        return 1;
    }
}

FutureTask实现了RunnableFuture接口,RunnableFuture继承了RunnableFuture接口。所以也是间接通过Runnable来创建的。

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交执行:Future result1 = ser.submit(t1);
  • 获取结果: boolean r1 = result1.get()
  • 关闭服务: ser.shutdownNow();

实现Runnable接口和Callable接口的区别

  • Runnable 接口不会返回结果,Callable 接口可以返回结果
  • Callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是runnable接口实现类中run方法的异常必须在内部处理,不能抛出

线程池

ThreadPoolExecutor类的execute方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEKGtqyC-1677038180765)(Java%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%B1%87%E6%80%BB%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0.assets/image-20230222115102680.png)]

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    int c = ctl.get();
    //如果工作线程数小于核心线程数,
    if (workerCountOf(c) < corePoolSize) {
        //执行addWorker,会创建一个核心线程,如果创建失败,重新获取ctl
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //如果工作线程数大于等于核心线程数,线程池的状态是RUNNING,并且可以添加进队列
    //(RUNNING状态下)如果添加失败,说明是队列已经满了,接着就去创建新的线程,如果大于最大线程数,则执行拒绝策略
    //如果线程池不是RUNNING状态,则执行拒绝策略(当然还会调addWorker进行判断一次)
    if (isRunning(c) && workQueue.offer(command)) {
        //再次获取ctl,进行双重检索(也就是对线程池的状态再次检查一遍)
        int recheck = ctl.get();
        //如果线程池是不是处于RUNNING的状态,那么就会将任务从队列中移除,
        //如果移除失败,则会判断工作线程是否为0 ,如果过为0 就创建一个非核心线程
        //如果移除成功,就执行拒绝策略,因为线程池已经不可用了;
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        //线程池挂了或者大于最大线程数
        reject(command);
}

addWork方法会创建线程池内工作线程WorkerWorker这个线程,实现了Runnable接口,并持有一个线程thread,一个初始化的任务firstTask。thread是调用构造方法时通过ThreadFactory来创建的线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TG3ITFgx-1677038180766)(Java%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%B1%87%E6%80%BB%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0.assets/image-20230222113722589.png)]

ThreadFactory中也是Runnable创建线程的模式。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/363011.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目精选】动漫论坛的设计与实现(论文+视频+源码)

点击下载源码 作为文化产业的一部分&#xff0c;动漫影响了我国一代又一代青少年&#xff0c;据钱江晚报调查显示&#xff0c;有超过七成的95后愿意从事与动漫相关的行业&#xff0c;可见其对青少年影响力之大。 动漫论坛作为最先开始热爱动漫人士进行交流的方式之一&#xff0…

让师生“不跑腿”,教育数据治理究竟有何魔力

当前&#xff0c;教育信息化新基础设施正在加紧建设&#xff0c;教育业务系统应用不断推进&#xff0c;各种软硬件平台源源不断地产生着教育数据。海量数据的汇聚和分析&#xff0c;能给教育系统带来什么&#xff1f;如何在教育数字化转型中&#xff0c;探索出基于数据驱动的新…

Linux 浅谈之性能分析工具 perf

Linux 浅谈之性能分析工具 perf HELLO&#xff0c;各位博友好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 这里是 Linux 浅谈系列&#xff0c;收录在操作系统专栏中 &#x1f61c;&#x1f61c;&#x1f61c; 本系列将记录一些阿呆个人整理的 OS 相关知识…

【数据结构入门】-链表之单链表(1)

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【数据结构初阶&#xff08;C实现&#xff09;】 文章标题回顾链表链表的概念及结构各种节点打印链表尾插创建节点尾删头插头删查找在pos…

微信小程序 Vue+uniapp+nodejs早教育教幼教知识学习系统

目 录 1绪论 1 1.1项目研究的背景 1 1.2开发意义 1 1.3项目研究现状及内容 5 1.4论文结构 5 2开发技术介绍 7 2.5微信小程序技术 8 3系统分析 9 3.1可行性分析 9 3.1.1技术可行性 9 3.1.2经济可行性 9 3.1.3操作可行性 10 3.2网站性能需求分析 10 3.3网站功能分析 10 3.4系统…

PHP7.4 FFI 扩展安全问题

在前面 [极客大挑战 2020] 的Roamphp5-FighterFightsInvincibly 题&#xff0c;遇到了 FFI扩展 调用函数进行rce to bypass disable_function&#xff0c;之前没遇见过&#xff0c;刚好借此机会学一学 目录 <1> PHP 7.4 FFI简介 <2> FFI 配置信息 <3> FF…

数据库丨TiDB集群中高危Grafana权限漏洞如何快速修复?答案在这里→

文章目录前言一、现有TiDB信息二、下载解压Grafana组件1.下载2. 解压安装三、制作离线镜像源1.制作镜像2.离线镜像发布3.查看当前镜像源&#xff0c;设置镜像源境准备4.备份private.json5.publish镜像6.各个参数解释如下&#xff1a;7.清理老文件四、Grafana组件升级替换Grafan…

记数据血缘前端中panzoom初始化缩放比例的问题探索

0. 背景 有人问我 血缘前端vue版本能不能改初始缩放比例&#xff0c;节点太多的情况下初始缩放比例太大导致无法看清全图&#xff0c;需要渲染完之后手动缩放才能。 当时编写代码的时候使用 panzoom这个库来完成 血缘图的缩放工作。 使用的panzoom版本是&#xff1a; “panzoo…

nacos启动失败(解决方法汇总)

安装nacos 报错 org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name instanceOperatorClientImpl defined in URL [jar:file:/H:/nacos/nacos/target/nacos-server.jar!/BOOT-INF/lib/nacos-naming-2.0.3.jar!/com/alibaba/na…

【数据结构与算法】哈希表2:四数相加II 赎金信 三数之和 四数之和

文章目录今日任务1.Leetcode454.四数相加II&#xff08;1&#xff09;题目&#xff08;2&#xff09;思路&#xff08;3&#xff09;代码演示2.Leetcode383.赎金信&#xff08;1&#xff09;题目&#xff08;2&#xff09;思路&#xff08;3&#xff09;暴力解法&#xff08;4&…

算法刷题日志——移除元素,双指针

文章目录删除有序数组中的重复项[删除有序数组中的重复项 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/)移除元素[283. 移动零](https://leetcode.cn/problems/move-zeroes/description/)[844. 比较含退格的字符串](https://leetcode.cn/problem…

数仓、数据湖、湖仓一体、数据网格的探索与研究

第一代&#xff1a;数据仓库 定义 为解决数据库面对数据分析的不足&#xff0c;孕育出新一类产品数据仓库。数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合&#xff0c;用于支持管理决策和信息的全局共享。 数…

【Linux系统】认识操作系统和操作系统如何进行管理以及进程相关状态

进程概念1 认识冯诺依曼体系结构1.1 冯诺依曼体系结构存储器的作用2 操作系统(Operator System&#xff0c;OS)2.1 OS如何进行管理3 进程3.1 OS管理进程&#xff1a;先描述再组织3.2 描述进程-PCB3.3 查看进程3.4 通过系统调用获取进程标识符3.5 通过系统调用创建子进程——for…

vue+echarts:柱状图横向展示和竖向展示

第021个点击查看专栏目录本示例是显示柱状图&#xff0c;分别是横向展示和纵向展示。关键是X轴和Y轴的参数互换。 文章目录横向示例效果横向示例源代码&#xff08;共81行&#xff09;纵向示例效果纵向示例源代码&#xff08;共81行&#xff09;相关资料参考专栏介绍横向示例效…

什么是真正的骨传导耳机,骨传导耳机原理

骨传导耳机大多采用后挂耳/夹耳佩戴方式&#xff0c;但现在很多人分不清哪些是骨传导耳机&#xff0c;哪些是气传导耳机。看完这篇教会你辨别哪些是真正的骨传导耳机。 骨传导耳机采用固体传声方式&#xff0c;整个耳机机身都没有传声音孔的设计&#xff0c;主要通过耳机振子发…

Retrofit+Hilt后端请求小项目3--Retrofit代码完善

目录ApiConstants定义实体类定义 API 接口定义 Repository定义 ApiModule定义 Application定义 ViewModelApiConstants 这一块存放 API 常量&#xff0c;即后端服务器 BASE_URL&#xff0c;以及对应的后缀 URL 代码清单&#xff1a;data/api/ApiConstants.kt object ApiConsta…

最纯净-Ubuntu系统下如何卸载kubernetes(k8s)-2023最新

首先&#xff0c;如果是卸载k8s-1.24以上版本&#xff0c;需要单独卸载containerd&#xff1a; sudo apt-get purge --auto-remove containerd.io1. 步骤 其他步骤如下&#xff1a; 执行命令&#xff1a; kubeadm reset -fsudo apt-get purge --auto-remove kubernetes…

港科夜闻|广东省省长王伟中会见香港科技大学访问团

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、广东省省长王伟中会见香港科技大学访问团。2月17日&#xff0c;广东省省长王伟中先生在广州与香港科大校董会主席廖长城先生、校董会副主席杨佳锠教授、校长叶玉如教授就加强教育合作、科技创新等进行深入交流。王伟中先生表…

华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】

刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…

特征与处理-sklearn归一化、标准化、缺失值处理

目录 特征的预处理 归一化 标准化 缺失值 特征的预处理 特征处理定义&#xff1a;通过特定的二统计方法&#xff08;数学方法&#xff09;将数据转换成算法要求的数据 归一化 sklearn归一化API&#xff1a;sklearn.preprocessing.MinMaxScaler from sklearn.preprocessing i…