多线程的三种创建方式及各自的优缺点分析

news2024/11/24 2:11:13

第一种方式:继承Thread类,覆写run()方法

1、创建一个MyThread类,继承Thread类;
2、覆写run()方法,在run()方法内编写任务代码;
3、创建MyThread类,需要注意的是,如果想要给线程命名,需要在MyThread类中创建构造方法,在构造方法内调用父类Thread的有参构造
4、启动线程

/**
 * 多线程的第一种创建方式
 */
public class EssayTest01 {
    public static void main(String[] args) {
        // 创建两个继承了Thread的类对象,并启动
        MyThread t1 = new MyThread("线程1");
        MyThread t2 = new MyThread("线程2");

        // 启动线程
        t1.start();
        t2.start();
    }
}

/**
 * 创建一个类,继承Thread类,覆写run()方法
 */
class MyThread extends Thread {
    /**
     * 如果要给线程命名,这里需要调用Thread中的有参构造方法
     */
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第一种创建方式:运行第" + (i + 1) + "次");
        }
    }
}

在这里插入图片描述

第二种方式:实现Runnable接口,实现run()方法,再创建Thread对象

1、创建一个MyRunnable类,实现Runnable接口;
2、实现run()方法,在run()方法内编写任务代码;
3、创建MyRunnable类对象
4、创建Thread线程类对象,将MyRunnable对象作为参数传入
5、启动线程

/**
 * 多线程实现方式2:实现Runnable接口
 */
public class EssayTest02 {
    public static void main(String[] args) {
        // 创建MyRunnable对象
        MyRunnable mr = new MyRunnable();

        // 创建线程对象并设置线程名,将MyRunnable对象作为参数传入
        Thread t1 = new Thread(mr, "线程1");
        Thread t2 = new Thread(mr, "线程2");

        // 启动线程
        t1.start();
        t2.start();
    }

}

/**
 * 创建一个类,实现Runnable接口,实现run()方法
 */
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
        }
    }
}

在这里插入图片描述

另外,可以使用匿名内部类+lambda表达式的方式实现,如下:

/**
 * 多线程实现方式2:实现Runnable接口,用匿名内部类+lambda表达式
 */
public class EssayTest02 {
    public static void main(String[] args) {

        // 创建线程对象并设置线程名,将MyRunnable对象作为参数传入
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                System.out.println(Thread.currentThread().getName() + " 这是多线程的第二种创建方式:运行第" + (i + 1) + "次");
            }
        });

        // 启动线程
        t1.start();
        t2.start();
    }
}

但需要注意的是,这样就不能让两个线程对同一资源进行操作了
在这里插入图片描述

第三种方式:实现Callable接口,实现call()方法,再创建FutureTask来管理后面创建的Thread对象

1、创建一个MyCallable类,实现Callable接口;
2、实现call()方法,在call()方法内编写任务代码;
3、创建MyCallable类对象
4、创建FutureTask对象,将MyCallable对象作为传入
5、创建Thread线程对象,将FutureTask对象作为参数传入
6、启动线程

需要注意的是,
(1)FutureTask泛型的类型要与call()方法的返回值,即Callable指定的泛型一致;
(2)使用FutureTask对象的get()方法获取线程的返回值,要在线程启动start()方法的后面,不然程序会干瞪眼,不会输出任何结果

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 多线程创建方式3:实现Callable接口,实现call()方法,再创建FutureTask来管理后面创建的Thread对象
 */
public class EssayTest03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建MyCallable对象
        MyCallable mc = new MyCallable();

        // 创建FutureTask对象,将MyCallable对象作为传入传入,FutureTask对象的泛型要与Callable的一致
        FutureTask<String> ft = new FutureTask<String>(mc);

        // 创建线程,将FutureTask作为参数传入
        Thread t = new Thread(ft);

        // 启动线程
        t.start();

        // 通过get()方法获取线程的返回值,注意要放在start()后面
        System.out.println(ft.get());
    }
}

/**
 * 创建一个类,实现Callable接口,实现call()方法,注意call()方法的泛型指的是方法的返回值类型
 */
class MyCallable implements Callable<String> {

    @Override
    public String call() throws Exception {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + " 这是多线程的第三种创建方式:运行第" + (i + 1) + "次");
        }
        return "success";
    }
}

在这里插入图片描述

总结

第一种创建方式:逻辑简单,结构清晰,便于理解;但耦合高,每个对象都和MyThread直接关联,而且如果要设置线程名,还必须创建一个有参的构造方法

第二种创建方式:使用lambda表达,可以简化代码,解耦合;但如果涉及到多个线程对同一资源处理,就不能使用lambda表达式的方式了,另外线程没有返回值,无法知道线程运行结果

第三种创建方式:功能强大,可以返回线程运行的结果;但结构复杂,不易理解

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

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

相关文章

传染病学模型 | Matlab实现SI传染病学模型 (SI Epidemic Model)

文章目录 效果一览基本描述模型介绍程序设计参考资料效果一览 基本描述 传染病学模型 | Matlab实现SI传染病学模型 (SI Epidemic Model) 模型介绍 SI传染病模型是一种基于微分方程的流行病学模型,用于模拟传染病在人群中的传播过程。SI模型中,人群被划分为易感者(S)和感染者…

来 Azure 学习 OpenAI 四 - 用 Embedding 赋能 GPT

大家好&#xff0c;我是学生大使 Jambo。在我们前一篇文章中&#xff0c;我们介绍了 OpenAI 模型的调用。今天&#xff0c;我将为大家介绍 Embedding 的使用。 嵌入是什么 嵌入&#xff08;Embedding &#xff09;是一种将高维数据映射到低维空间的方法。嵌入可以将高维数据可…

第一章 初识Python

1.1 课前必读 课程大纲 1.2 Python介绍 Python特点&#xff1a; 主流语言&#xff1b;用途广泛&#xff0c;号称万能语言&#xff1b;上手简单&#xff1b; Python用途&#xff1a; 数据挖掘&#xff08;爬虫&#xff09;和数据分析自动化脚本编写&#xff08;软件测试人员使用…

尚硅谷周阳老师 SpringCloud第二季学习笔记

前言&#xff1a;首先感谢尚硅谷周阳老师的讲解&#xff0c;让我对springcloud有了很好的理解&#xff0c;周阳老师的讲课风格真的很喜欢&#xff0c;内容充实也很幽默&#xff0c;随口一说就是一个段子&#xff0c;我也算是周阳老师的忠实粉丝啦。 先说说课程总体内容 以下是…

[学习笔记] [机器学习] 6. [上]决策树算法(熵Entropy、信息增益(率)、基尼值(指数)、CART剪枝、特征工程特征提取、回归决策树)

视频链接数据集下载地址&#xff1a;无需下载 学习目标&#xff1a; 掌握决策树实现过程知道信息熵的公式以及作用知道信息增益、信息增益率和基尼指数的作用知道id3、c4.5、cart算法的区别了解cart剪枝的作用知道特征提取的作用应用DecisionTreeClassifier实现决策树分类 1…

开放原子训练营(第三季)inBuilder低代码开发实验室,低代码到底该长什么样

目录 前言&#xff1a; 一、什么是inBuilder低代码开发实验室 二、技术特征 2.1开放性 2.2开发语言无关性 2.3云原生 2.4模型工程化 2.5全栈模型刻画 2.6运行态定制 2.7仓库介绍 三、快速入门 四、实操案例 4.1定义数据源 4.2 设计页面 4.3发布调试 五、总结 前言&#xf…

Activiti实战——Springboot整合Activiti

目录 一、Activiti数据库表名说明 二、Spring boot整合activiti 1. 创建springboot项目 2. 引入activiti依赖及项目依赖 3. 配置数据源 &#xff08;1&#xff09;创建数据源配置文件 &#xff08;2&#xff09;配置文件 4. 配置Acitviti引擎 5. 启动项目 三、Activiti…

【MySQL 数据库】1、MySQL 的 DDL、DML、DQL 语句

目录 一、MySQL 应该掌握哪些知识点 &#xff1f;二、数据库相关概念三、主流关系型数据库管理系统四、关系型数据库五、SQL 语句的分类六、DDL(1) 数据库操作(2) 表操作(3) 字段的数据类型(4) 创建员工表(5) 修改表结构(6) 删除某一张表 七、DML八、DQL(1) 员工表(2) distinct…

经典神经网络(4)Nin-Net及其在Fashion-MNIST数据集上的应用

经典神经网络(4)Nin-Net及其在Fashion-MNIST数据集上的应用 1 Nin-Net的简述 1.1 Nin-Net的概述 LeNet、AlexNet和VGG都有⼀个共同的设计模式&#xff1a;通过⼀系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进⾏处理。AlexNet和VGG对Le…

线程池的创建与使用

void execute(Runnable run)方法处理Runnbale任务 Future<> submit(Callable<> task)方法处理Callable任务 void shutdown()结束线程池 List<\Runnable> shutdownNow()立即结束线程池&#xff0c;不管任务是否执行完毕 //创建线程池的一种方式 ExecutorServi…

基于WebApi实现ModbusTCP数据服务

在上位机开发过程中&#xff0c;有时候会遇到需要提供数据接口给MES或者其他系统&#xff0c;今天跟大家分享一下&#xff0c;如何在Winform等桌面应用程序中&#xff0c;开发WebApi接口&#xff0c;提供对外数据服务。 为了更好地演示应用场景&#xff0c;本案例以读取Modbus…

Leetcode 209. 长度最小的子数组——go语言实现

文章目录 一、题目描述二、代码实现方法一&#xff1a;暴力法解题思路代码实现复杂度分析 方法二&#xff1a;滑动窗口 双指针解题思路代码实现复杂度分析 方法三&#xff1a;前缀和 二分查找解题思路代码实现复杂度分析 一、题目描述 给定一个含有 n 个正整数的数组和一个正…

STM32 10个工程篇:1.IAP远程升级(四)

在前三篇博客中主要介绍了IAP远程升级的应用背景、下位机的实现原理、以及基于STM32CubeMX对STM32F103串口DMA的基本配置&#xff0c;第四篇博客主要想介绍Labview端上位机和下位机端的报文定义和通信等。 当笔者工作上刚接触到STM32 IAP升级的时候&#xff0c;实事求是地说存在…

【科普】电压和接地真的存在吗?如何测试?

经常在实验室干活的&#xff0c;难免不被电击过&#xff0c;尤其是在干燥的北方&#xff0c;“被电”是常有的事情&#xff0c;我记得有一次拿着射频线往仪表上拧的时候&#xff0c;遇到过一次严重的电火花&#xff0c;瞬间将仪表的射频口边缘烧出了一个疤&#xff0c;实验室遭…

LeetCode83. 删除排序链表中的重复元素

写在前面&#xff1a; 题目链接&#xff1a;LeetCode83. 删除排序链表中的重复元素 编程语言&#xff1a;C 题目难度&#xff1a;简单 一、题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 …

Java中异常的处理及捕获

Java中异常的处理及捕获 一、异常的概述 &#xff08;1&#xff09;Java中异常的作用&#xff1a;增强程序的健壮性 &#xff08;2&#xff09;在Java中所有的Error&#xff08;错误&#xff09;和异常&#xff08;Exception&#xff09;都继承了同一个父类Throwable 二、异…

postgresql内核源码分析-删除表drop table流程

专栏内容&#xff1a;postgresql内核源码分析个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 调用关系 概要流程 详细流程 创建对象列表空间 删除多个指定的数据库…

【蓝桥杯国赛真题27】Scratch LED屏幕 少儿编程scratch图形化编程 蓝桥杯国赛真题讲解

目录 scratch LED屏幕 一、题目要求 编程实现 二、案例分析 1、角色分析

C#中使用git将项目代码上传到远程仓库的操作

一、远程仓库创建操作&#xff08;远程仓库使用的是gitHub&#xff09; 1、登录GitHub官网&#xff0c;注册登录账号后&#xff0c;点击创建仓库 2、仓库名称命名&#xff0c;如下所示&#xff1a; 3、创建成功如下所示&#xff1a;获得https协议&#xff08;https://github.c…

Android开发不可缺少的辅助工具

目录 jadxandroid_toolscrcpy-guiCode CraftsSQLite Expert Personal jadx jadx是一款apk反编译工具。 PS&#xff1a;部分版本安装&#xff0c;无法打开类文件&#xff0c;需换个版本。 开源地址&#xff1a;https://github.com/skylot/jadx android_tool android_tool可以通…