多线程——认识线程(Thread)

news2024/12/26 23:16:36

目录

·前言

一、第一个多线程程序

1.程序编写

2.介绍jconsole

二、创建线程

1.继承Thread类

①重写run方法

②重写run方法,使用匿名内部类

2.实现Runnable接口

①重写run方法

②重写run方法,使用匿名内部类

③使用 lambda 表达式

三、多线程的优势

·结尾


·前言

        在前面文章我介绍了线程是什么,线程存在的意义还有线程与进程的区别,在本篇文章将会带大家在Java中进一步认识线程,会用Java语言写第一个多线程的程序,介绍在Java中如何创建线程,还要结束多线程编程的优势。

一、第一个多线程程序

1.程序编写

        在下面的程序中,我会让大家感受到多线程程序和普通程序的区别:

  1. 每个线程是独立的执行流;
  2. 多个线程之间是“并发”执行的。

         程序代码如下所示:

// 1. 创建自己的类,继承自 Thread
class MyThread extends Thread {
    // run 方法是该线程的入口方法
    @Override
    public void run() {
        while (true) {
            // currentThread.getName()这个方法是获取当前线程的名字
            System.out.println("hello " + currentThread().getName());
            try {
                // sleep()这个方法会让当前线程进入休眠,()中参数是ms,为了减慢循环频率
                // 这个方法可能抛出异常,所以需要用 try-catch包住
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        // 2. 根据上面创建的类,创建出实例
        Thread t1 = new MyThread();
        // 3. start(),这个方法用来启动线程,这才是创建出线程
        //    调用这个方法,才会真正调用系统 api ,在系统内核中创建出线程
        t1.start();

        // 在main里启动另一个死循环,直观感受两个线程在"并发"执行
        while (true) {
            System.out.println("hello " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

        程序运行结果如下图所示:

        由上图两个线程中的循环不断打印里面的内容,可以看出这两个线程是“并发”执行。

2.介绍jconsole

        jconsole是一个很方便的工具,可以利用这个工具来查看我们创建线程的相关信息,他的位置在我们的jdk的bin目录下,如下图所示:

        下面介绍一下jconsole的使用过程:

        关于使用jconsole需要补充介绍几点:

  1. jconsole 只能列出Java的进程,其他不是Java的程序无法分析;
  2. 打开 jconsole 可能不显示任何进程,可以使用管理员的方式来启动 jconsole(鼠标右键选择jconsole,选择“以管理员的身份运行”);
  3. 上面图中可以看见,我们创建的线程名叫 Thread-0 ,但是代码中,实例化的对象名叫t,其实答案就在刚才说的话里,我们创建的是一个对象,t是对象的名,不是我们所创建的线程名,我们创建的线程名默认叫 Thread-0、Thread-1……;
  4. 上图中,我们会发现,除了我们手动创建的线程,和main线程外,还有很多别的线程,这些线程都是JVM自带的线程,他们需要完成一些其他工作,比如垃圾回收,监控统计各种指标(如果代码出问题,可以通过这些指标给我们提供一些线索)等……;
  5. 线程是不断执行的,jconsole 是在我们选择线程的一瞬间,对线程来个“快照”,就把这一瞬间的状态展开显示出来。

        其实不光是 jconsole 可以看到线程的情况,在 idea 调试器中,也可以看道线程的情况,只不过我个人感觉 jconsole 比较方便,所以就不再介绍 idea 中的调试器了。

二、创建线程

        下面我来介绍几种Java中创建线程的方式:

1.继承Thread类

①重写run方法

// 继承 Thread 重写 run 方法
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello thread!!!");
    }
}

public class ThreadDemo2 {
    public static void main(String[] args) {
        // 实例化一个线程对象
        Thread t = new MyThread();

        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

②重写run方法,使用匿名内部类

// 继承 Thread ,重写 run 方法,使用匿名内部类
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            // 指定线程任务
            @Override
            public void run() {
                System.out.println("hello thread");
            }
        };

        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

2.实现Runnable接口

①重写run方法

// 创建一个 Runnable 的实现类,并实现 run 方法
// Runnable 主要描述的是线程的任务
class MyThread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("hello thread!!!");
    }
}

public class ThreadDemo4 {
    public static void main(String[] args) {
        // 实例化 Runnable 对象
        Runnable runnable = new MyThread2();
        // 实例化线程对象,并绑定任务
        Thread t = new Thread(runnable);
        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

②重写run方法,使用匿名内部类

// 通过 Runnable 匿名内部类创建一个线程
public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            // 指定线程任务
            @Override
            public void run() {
                System.out.println("hello thread!!!");
            }
        });
        // 申请系统线程参与CPU调度
        t.start();
    }
}

③使用 lambda 表达式

        lambda表达式可以简化函数式接口的使用。什么是函数式接口呢?就是一个有且只有一个抽象方法的普通接口,Runnable接口就是一个函数式接口,所以可以使用 lambda 表达式来创建 Runnable 的子类对象,进而创建一个线程,代码如下所示:

// 通过 lambda 表达式的方式创建一个线程
public class ThreadDemo6 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            // 指定任务: 打印 hello thread!!
            System.out.println("hello thread!!");
        });
        // 申请系统线程参与CPU调度
        t.start();
    }
}

        上述的五种创建线程的方式,我本人比较喜欢用 lambda 表达式的方式进行创建线程,因为这种方式比较简便。 

三、多线程的优势

        使用多线程的方式可以加快运行速度,可以举一个例子,如下图所示:

        在一个房间中,有100只烤鸡,此时需要房间中的滑稽老哥把这些鸡给吃完,可想而知,这样吃下去的速度会很慢,为了加快吃鸡效率,我们可以再邀请一个个滑稽老哥一起吃鸡,如下图所示: 

        这样,一个滑稽老哥吃50只烤鸡,效率明显就快了很多,以此类推,我们还可以再多邀请几个滑稽老哥,如下图所示:         现在,邀请了更多的滑稽老哥,吃鸡的速度变得更快了,但是,不是说引入的滑稽老哥越多效率就会越快,如下图所示:

        上图我们可以看出,邀请的滑稽老哥到达一定数量之后,再邀请更多的滑稽老哥,吃鸡的效率也没有办法继续提升了,这是因为桌子坐不下了。

        上面列举的例子中,滑稽老哥就是我们的线程,烤鸡就是我们要执行的任务,多线程的优势就是通过引入多个线程可以加快执行任务的效率,但是也不能引入太多的线程,就像上图所示那样,线程数量太多,各个线程之间就会互相竞争CPU的资源(CPU核心数有限),这样非但不会提高效率,反而还会增加调度的开销。 

·结尾

        文章到这就快结束了,本篇文章是在Java中利用多线程编程的一个初始篇章,这里介绍了创建线程的几种方式,编写的第一个多线程程序,介绍了多线的优势,在下一个篇文章中我会对java中Thread类再进行进一步的讲解,如果本篇文章对你有帮助的话,希望能三连支持一下咯,您的支持就是我最大的动力,我们下一篇文章再见吧,┏(^0^)┛~~~

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

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

相关文章

【吊打面试官系列-MySQL面试题】为表中得字段选择合适得数据类型

大家好,我是锋哥。今天分享关于【为表中得字段选择合适得数据类型】面试题,希望对大家有帮助; 为表中得字段选择合适得数据类型 字段类型优先级: 整形>date,time>enum,char>varchar>blob,text 优先考虑数字类型,其次是…

c++类与对象二

文章目录 C类与对象二类的实例化类对象内存大小计算this指针特性 C类与对象二 类的实例化 用类创建对象的过程,称之为类的实例化 类是对对象进行描述的,限定了类有哪些成员,定义一个类并没有开辟内存空间。例如需要学生填写的个人表格&…

js 如何获取当日零点整的时间戳

最近遇到个问题需要取当日的零点整的时间戳去存取日程 上代码: const timestr new Date().setHours(0, 0, 0, 0) console.log(timestr) 效果展示: Tips:除了 Java 以外的语言需要除以1000 具体视情况而定 Java、js的时间戳都是毫秒级的…

每日一练:腐烂的橘子

994. 腐烂的橘子 - 力扣(LeetCode) 题目要求: 在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一: 值 0 代表空单元格;值 1 代表新鲜橘子;值 2 代表腐烂的橘子。 每分钟&#xf…

leetcode35--搜索插入位置--二分查找刷题

搜索插入位置 一共会出现下面四种情况: 目标值在数组所有元素之前 目标值等于数组中某一个元素 目标值插入数组中的位置 目标值在数组所有元素之后 首先在二分查找的代码之前处理掉目标值在数组所有元素之前和之后的情况如果目标值在数组中的某个位置&#xff0c…

51单片机系列-按键检测原理

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 独立按键是检测低电平的。 下面我们来看一张对应的电路原理图: 在这张图当中,P1,P2,P3内部都上拉了电阻,但是P0没有&am…

学习记录:js算法(四十九):二叉树的层序遍历

文章目录 二叉树的层序遍历网上思路队列循环 总结 二叉树的层序遍历 给你二叉树的根节点 root ,返回其节点值的层序遍历 。 (即逐层地,从左到右访问所有节点)。 图一: 示例 1:如图一 输入:roo…

【QT】亲测有效:“生成的目标文件包含了过多的段,超出了编译器或链接器允许的最大数量”错误的解决方案

在使用dlib开发人脸对齐功能时&#xff0c;出现了”生成的目标文件包含了过多的段&#xff0c;超出了编译器或链接器允许的最大数量的错误“。 主要功能代码如下&#xff1a; #include <QApplication> #include <QImage> #include <QDebug>#include <dlib…

叶绿素透射反射率与波长

本文在分析巢湖水体反射光谱特征的基础上,通过对光谱反射率与叶绿素a 的浓度之间的关系进行分析研究,结果表明,单波段光谱反射率与叶绿素a浓度的相关系数较小,不宜用于估算叶绿素a浓度&#xff0e;光谱反射率比值RFo5.m/Rss.nm.和 690nm反射率的一阶微分均与叶绿素a浓度有较好的…

leetcode每日一题day16(24.9.26)——数组元素和与数字和的绝对差

思路&#xff1a;遍历数组在对数组元素进行求和时并使用while循环求数字和&#xff0c;由于对于一个数&#xff0c;其必定大于其个数位数字的和,所以可以直接对sum进行减 代码 int differenceOfSum(vector<int>& nums) {int ans 0;for (int x : nums) {ans x; // …

基于Springboot+Vue的玩具租赁系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

OpenSCAP部署、使用与原理分析

文章目录 前言1、概述2、安装与使用2.1、源码安装2.1.1、获取源代码2.1.2、获取构建依赖项2.1.3、构建库2.1.4、构建HTML文档2.1.5、运行测试2.1.6、安装OpenSCAP2.1.7、安装SCAP内容 2.2、使用方法2.2.1、oscap的常用命令2.2.2、显示有关SCAP内容的信息2.2.2.1、显示有关SCAP源…

WITS核心价值观【创新】篇|系统进化论 解锁新纪元

「客尊」、「诚信」、「创新」 与「卓越」 是纬创软件的核心价值观。我们秉持诚信态度&#xff0c;致力于成为客户长期且值得信赖的合作伙伴。持续提升服务厚度&#xff0c;透过数字创新实践多市场的跨境交付&#xff0c;助客户保持市场领先地位。以追求卓越的不懈精神&#xf…

【Python报错已解决】 WARNING: Ignoring invalid distribution

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

【JavaSE】反射、枚举、lambda表达式

目录 反射反射相关类获取类中属性相关方法常用获得类相关的方法示例常用获得类中属性相关的方法示例获得类中注解相关的方法 反射优缺点 枚举常用方法优缺点 枚举与反射lambda表达式语法函数式接口简化规则使用示例变量捕获集合中的应用优缺点 反射 Java的反射&#xff08;refl…

数据分析-30-电影死亡笔记中的数据分析思维

文章目录 1 死亡笔记简介2 推理过程中的数据分析2.1 第一个问题2.2 第二个问题2.3 第三个问题3 数据分析的发展4 参考附录1 死亡笔记简介 《死亡笔记》改编自小畑健同名日本人气漫画《Death note》,故事描述拥有一本写上姓名就能将人置于死地笔记本的高中生夜神月与天才警部搜…

人工智能迭代产品有哪些

人工智能迭代产品有很多&#xff0c;以下是一些例子&#xff1a; Ai 智能办公利器 - Ai-321.com 人工智能 - Ai工具集 - 集合全球ai人工智能软件的工具箱网站 Midjourney&#xff1a;这是一款基于AI技术的文生图产品&#xff0c;可以通过简单的prompt生成独具艺术感的 Midjo…

工具按钮 QToolButton

工具按钮常常用来显示图标&#xff0c;然后添加到工具栏中 常用属性和方法 文本 设置和获取文本 //设置和获取文本 QString text() const void setText(const QString &text)图片 设置和获取图片 //设置和获取图片 QIcon icon() const void setIcon(const QIcon &…

【STM32单片机_(HAL库)】4-0【定时器TIM】定时器中断配置步骤

定时器工作原理 定时器计数模式 定时器溢出时间计算 定时器中断实验配置步骤 msp 函数是对 MCU 相关的硬件进行初始化设置&#xff0c;通常被设计用于处理特定硬件外设或功能的底层初始化工作。

Spring Boot驱动的足球青训俱乐部管理解决方案

1 绪论 1.1研究背景 随着科技的发展&#xff0c;计算机的应用&#xff0c;人们的生活方方面面都和互联网密不可分。计算机的普及使得人们的生活更加方便快捷&#xff0c;网络也遍及到我们生活的每个角落&#xff0c;二十一世纪信息化时代的到来&#xff0c;随着社会科技的不断…