<多线程章节二>创建线程的几种常见方式

news2024/12/17 9:33:02

文章专栏

本篇文章收录于多线程,也欢迎翻阅博主的其他文章,可能也会让你有不一样的收获😄
💡JavaSE语法 💡数据结构 💡多线程

💡专栏导读

操作系统提供了一些API来操作线程,Java针对这些API进行了封装,所以只要掌握了这一套API就可以了,在Java中,JVM使用Thread类管理线程, 换句话讲,每一个Thread对象都对应一个线程,JVM将这些Thread对象组织起来进行调度执行, 想要使用线程,只要学习这个类中的方法就可以了

💐创建线程的五种方式

方法解释
Thread()创建线程对象
Thread(String name)创建线程对象,并给线程命名,不会影响线程
Thread(Runnable runnable)使用Runnable对象创建线程
Thread(Runnable runnable, String name)使用Runnable对象创建线程并给线程命名

方式1.创建一个类,继承Thread

每一个线程都是一个单独的”执行流“, 都可以执行一段代码逻辑,但是,创建的线程从哪里开始执行呢???就需要提供一个入口,而run方法就是线程的入口,表示就从run方法这里开始执行;这一点就像是main方法一样,当运行一个Java程序时,就会从main方法开始执行代码;

此时,我们写的一个Java程序其实就是一个进程,一个进程里面至少要有一个线程,就是主线程,而在Java程序中,主线程的入口方法就是main方法;

//创建一个类,继承Thread
class MyThread extends Thread{
    //重写Thread里面的run方法,这个方法就是线程的入口
    @Override
    public void run() {
        //代码逻辑
    }
}
public class Demo1 {
    public static void main(String[] args) {
        
    }
}

但是,只有run方法还是不够的,run方法只是说明了线程从哪个地方开始执行,run方法里面只是定义了线程要做哪些任务,在主线程中,需要再调用start()方法来创建一个新的线程,线程创建后,再由线程调用run()方法开始执行任务;

//创建一个类,继承Thread
class MyThread extends Thread{
    //重写Thread里面的run方法,这个方法就是线程的入口
    @Override
    public void run() {
        System.out.println("线程正在工作");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        //run() 和 start() 都是Thread的方法
        //run()方法只是线程的入口
        //start()方法才是调用了系统API来创建一个线程,让线程再调用run来执行任务
    }
}

在这里插入图片描述

下面展示一个两个线程并发执行的情况:

class MyThread extends Thread{
    //重写Thread里面的run方法,这个方法就是线程的入口
    @Override
    public void run() {
        //写一个while循环让这个线程一直打印
        while(true) {
            System.out.println("hello Thread");
            try {
                //进行一个休眠方便观察
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();
        //写一个while循环,一直打印
        while(true) {
            System.out.println("hello main");
            //进行一个休眠方便观察
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

上述结果就可以看到,两个线程分别在执行自己的代码,这也就印证了每一个线程都是一个单独的”执行流“, 本来在运行时只有一个执行流,但是遇见 thread.start() ,就开始了兵分两路”同时执行“, 就达到了并发编程的效果,而这里的并发指的是”并行+并发“, 因为,程序员在写代码的时候,是无法感知到这两个线程到底是在一个CPU核心上调度执行还是在两个CPU核心上同时执行, 所以在宏观上也就是我们人的肉眼看着都是在同时执行的,这一点在进程那篇文章中已经讲解的很清楚了,你可以去看一下👈

如果讲代码中的 thread.start() 改为 thread.run() 会发生什么呢?

在这里插入图片描述

如果改成thread.run(), 它就只剩下一个主线程了,只会按照代码的顺序依次执行,就成了一个单独的方法调用,这就不是多线程工作了,只有当run()方法结束后,才会继续向下执行;也就没有实现”并发编程”;也可以看到,Runnable类中也是只有一个方法run();

在这里插入图片描述

方式2.创建一个类,实现Runnable接口

使用Runnable接口和继承Thread的区别就是为了解耦合,比如说,有一些任务不一定是线程调度执行,也有可能是线程池或着其他等等,这时候就可以把这个任务给抽离出来,直接就可以用线程池或其他;

//创建一个类,实现Runnable接口
class MyThread2 implements Runnable{
    @Override
    public void run() {
        while(true) {
            System.out.println("hello Thread");
        }
    }
}
public class Demo2 {
    public static void main(String[] args) {
        //Runnable 就表示的是这是一个可执行的任务
        Runnable runnable = new MyThread();
        Thread thread = new Thread(runnable);
        
        thread.start();
        
        while(true) {
            System.out.println("hello main");
        }
    }
}

方式3.继承Thread,重写run(), 但是使用匿名内部类

这个类没有名字,所以叫匿名内部类,虽然没有名字但是也没有关系,因为这个类是一次性的,只知道这个类是Thread的子类,然后同时又进行了实例化,之后在子类中重写run() 方法;如果你不理解匿名内部类,可以我这篇文章👉


    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("hello Thread");
            }
        };
        
        thread.start();
        System.out.println("hello main");
    }

方法4.实现Runnable,重写run(), 但是使用匿名内部类

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello Thread");
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
        System.out.println("hello main");
    }

方式5.使用Lambda表达式

    public static void main(String[] args) {
        
        Thread thread = new Thread(() -> {
            System.out.println("hello Thread");
        });

        thread.start();
        System.out.println("hello main");
    }

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

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

相关文章

python把ChestX-Det-Dataset的json样本转为COCO数据集的json格式

ChestX-Det-Dataset数据集网址:https://github.com/Deepwise-AILab/ChestX-Det-Dataset/tree/main 数据集JSON内容: [{"file_name": "36199.png","syms": [],"boxes": [],"polygons": []},{"f…

分享一下怎么做陪诊小程序

在当今快节奏的社会中,人们的生活压力越来越大,尤其是在大城市中,由于工作繁忙,生活节奏快,很多人都感到看病难、看病贵的问题。为了解决这一问题,陪诊小程序应运而生。陪诊小程序是一种可以提供线上预约、…

基于SSM民宿预订及个性化服务系统-计算机毕设 附源码 04846

SSM民宿预订及个性化服务系统 摘 要 伴随着国内旅游经济的迅猛发展民宿住宿行在国内也迎来了前所未有的发展机遇。传统的旅游模式已难以满足游客日益多元化的需求,随着人们外出度假的时间越来越长,导致人们在住宿的选择上更加追求舒适、个性化的住宿体验…

vue+Fullcalendar

vueFullcalendar: vueFullcalendar项目代码https://gitee.com/Oyxgen404/vue--fullcalendar.git

CSS样式(盒子模型,内外边距等设置)

盒子模型 目标:掌握盒子模型组成部分,使用盒子模型布局网页区域 01-选择器 结构伪类选择器 基本使用 作用:根据元素的结构关系查找元素。 选择器说明E:first-child查找第一个E元素E:last-child查找最后一个E元素E:nth-child(N)查找第N个E…

jquery-picture-cut 任意文件上传 (CVE-2018-9208)

jquery-picture-cut 任意文件上传 (CVE-2018-9208) 漏洞描述 picture cut是一个jquery插件,以非常友好和简单的方式处理图像,具有基于bootstrap或jquery ui的漂亮界面,具有ajax上传,从资源管理器拖动图像…

Error: no matching distribution found for tensorflow-cpu==2.6.*

目录 install_tensorflow()安装过程中遇到的问题 查找解决方案过程中: 解决办法: install_tensorflow()安装过程中遇到的问题 在服务器上安装tensorflow时,遇到了一个报错信息: 在网上找到一个类似的错误(TensorFlow…

【EI会议征稿】第二届纯数学、应用数学与计算数学国际学术会议(PACM 2024)

第二届纯数学、应用数学与计算数学国际学术会议(PACM 2024) 2024 2nd International Cnference on Pure, Applied and Computational Mathematics (PACM 2024) 第二届纯数学、应用数学计算数学国际学术会议 (PACM2024) 将于2024年1月19-21日在中国厦门隆…

利用a标签锚点定位实现切换页面的部分内容

最近在做一个数据可视化大屏的作业,其中需要实现点击不同的按钮,大屏中间内容呈现不同的数据分析图表,页面其他部分不发生改变。之前考虑过复制多个页面然后改变中间的页面,但是这样会导致文件冗余,而且由于静态文件放…

【机器学习项目实战案例目录】项目详解 + 完整源码

前言 大家好,我是阿光。 本专栏整理了《机器学习项目实战案例》,内包含了各种不同的入门级机器学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码。 正在更新中~ ✨ 🚨 我的项目环境: 平…

为什么要学Selenium自动化测试?

开发人员在编写代码时总是会考虑到不同的应用场景,但也可能会出现实现效果不如预期的情况。同样的原则也适用于测试代码,编写测试代码的主要目的是测试现有产品的功能、发现错误并使产品100%无错误。 有句话说得好:"真相总是比小说更离奇…

台积电2纳米黑科技 - 晶背供电 | 百能云芯

近期,台积电总裁魏哲家在一次法说会中透露了有关2纳米芯片的最新进展,并提到了“晶背供电”技术,这个领域的神秘黑科技正逐渐引起人们的兴趣。 在最近的台积电法说会上,总裁魏哲家不仅提到了2纳米制程的进展,还透露&am…

关于接口|常见电商API接口种类|接口数据类型|接口请求方法

常见接口种类# Http/Https接口: 通过http/https协议传送接口数据(通常按字符串/二进制传输), 如常见的网页表单, https安全性更好 RESTful Api: REST表述性状态传递. 一种设计风格,基于http/https协议, 把一切接口视为资源, 接口要分版本,在统一的域名下管理, 不同的方法(get…

MySQL索引揭秘,详解索引概念与作用,让你的数据库查询快如闪电

简介:MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。打个比方,如果合理的设计就像汉语字典的目录页,可以按拼音、笔画、偏旁部首等排序的目录快速查找到需要的字。数据库索引用于快速找出在数据…

若依进行tab页面切换时要求不刷新页面 vue3

若依进行tab页面切换时要求不刷新页面 vue3 看看个人中心怎么实现的 然后vue文件是这样的,注意大小写咯

C语言数据结构之数据结构入门

目录 数据结构介绍 数据结构发展史 何为算法 数据结构基础 基本概念和术语 四大逻辑结构(Logic Structure) 数据类型 理解复杂度概念 时间空间复杂度定义 度量时间复杂度的方法 程序运行时的内存与地址 编程预备 数据结构介绍 数据结构发展…

新框架Nue.js以及如何搭建框架(详细介绍)

先把官方文档已经github放在这里 链接: Nue官方文档👈点击即可跳转 链接: Nue官方github👈点击即可跳转 入门 NueJS是一个非常小(2.3kb minzipped)的JavaScript库,用于构建用户界面。它是Nue工具集的核心。它就像Vue.j…

工业级PoE交换机的工作原理

工业级POE交换机非常普遍,在许多供电不便的项目中被广泛使用,主要用于数据传输通信。大多数工业级POE交换机都是非网管型的,即插即用,配置简单,非常方便!然而,您了解它的工作原理吗?…

电机控制运放选型基本知识

概述 电机控制中一般使用运放搭配检流电阻实现电流采样。以下几个运放参数作为基本的考量对象。 共模电压和差模电压 共模电压 这个参数表示运放正负输入端分别对地的电压的平均值,即运放两端输入电压的中点电位,超过规格书限制的共模输入电压将损坏运…

Linux系统下的文件系统、各文件系统下目录结构及作用

要利用任何Linux系统,你需要对Linux的文件和目录(也称文件夹)了解。 Linux shell命令行中,文件和目录不是直观看见。需要使用:cd、ls、pwd等shell命令在目录之间切换。 Linux文件被收集到目录中,目录形成一个层级或树状结构: 一个目录可能包含其他目录,这些目录被称为子…