【Java多线程】多线程的三种实现方式和多线程常用方法

目录

1、多线程的三种实现方式

1.1、继承Thread类的方式进行实现

1.2、实现Runnable接口的方式进行实现

1.3、利用Callable接口和Future接口方式实现

1.4、三种实现方式的优缺点

2、多线程常用方法

1、多线程的三种实现方式

        在main()方法中,你可以创建和启动额外的线程,这些线程称为子线程。子线程可以并行执行,与主线程同时进行。多线程的三种实现方式如下:

  1. 继承Thread类的方式进行实现
  2. 实现Runnable接口的方式进行实现
  3. 利用Callable接口和Future接口方式实现

1.1、继承Thread类的方式进行实现

        java.lang.Thread是Java提供的线程类,继承了该类的就是一个线程类,所有的线程对象都必须是 Thread 类或其⼦类的实例。每个线程的作⽤是完成⼀定的任务,实际上就是执⾏⼀段程序流即⼀段顺序执⾏的代码,Java 使⽤线程执⾏体来代表这段程序流。主线程和分支线程是并发执行的,谁在前谁在后是随机的抢占式分配。Java中通过继承Thread类来创建并启动多线程的步骤如下:

        1. 定义 Thread 类的⼦类,并重写该类的 run() ⽅法,该 run() ⽅法的⽅法体就代表了线程需要完成的任务,因此把 run() ⽅法称为线程执⾏体。

        2. 创建 Thread ⼦类的实例,即创建了线程对象

        3. 调⽤线程对象的 start() ⽅法来启动该线程

定义线程,getName()方法可以在线程启动时获取线程的名字

public class MyThread extends Thread{
    @Override
    public void run() {
        //书写线程要执行代码
        for (int i = 0; i < 15; i++) {
            System.out.println(getName() + " Holle world");
        }
    }
}

创建线程对象,并启动线程,t1.setName("线程1"); t2.setName("线程2");可以给线程对象命名

public class ThreadDemo {
    public static void main(String[] args) {
        /*多线程的第一种启动方式:
            1.自己定义一个类继承Thread
            2.重写run方法
            3.创建子类的对象,并启动线程
         */
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}

运行结果

1.2、实现Runnable接口的方式进行实现

        采⽤ java.lang.Runnable 实现也是⾮常常⻅的⼀种,只需要重写 run ⽅法即可。

        步骤如下:

        1. 定义 Runnable 接⼝的实现类,并重写该接⼝的 run() ⽅法,该 run() ⽅法的⽅法体同样是该线程的线程执⾏体。

        2. 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是 真正的线程对象。

        3. 调⽤线程对象的 start() ⽅法来启动线程。

定义任务类,要实现Runnable接口,实现接口中的 run()方法

public class MyRun implements Runnable {
    @Override
    public void run() {
        //书写线程要执行代码
        for (int i = 0; i < 15; i++) {
            //currentThread()方法获取到当前线程的对象
            /*Thread t = Thread.currentThread();
            System.out.println(t.getName()+"HelloWorld!");
            */
            //把上面的两行代码改成链式编程的写法
            System.out.println(Thread.currentThread().getName() + " Holle world");
        }
    }
}

创建任务的对象,创建线程对象,并且把任务传递给线程对象,然后开启线程

public class ThreadDemo {
    public static void main(String[] args) {
        /*多线程的第二种启动方式:1.自己定义一个类实现Runnable接口
        2.重写里面的run方法
        3.创建自己的类的对象
        4.创建一个Thread类的对象,并开启线程
         */
        //创建MyRun的对象
        // 表示多线程要执行的任务
        MyRun mr = new MyRun();

        //创建线程对象,并且把任务传递给线程对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        //给线程设置名字
        t1.setName("线程1");
        t2.setName("线程2");
        //开启线程
        t1.start();
        t2.start();
    }
}

运行结果

1.3、利用Callable接口和Future接口方式实现

        Callable接口是Runable接口的增强版。同样用call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。

        Future接口用来代表Callable接口里的call()方法的返回值,FutureTask类是Future接口的一个实现类,FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask是一个提供异步计算的结果的任务。

        

        步骤如下:

                1.创建一个类MyCallable实现Callable接口
                2.重写call (是有返回值的,表示多线程运行的结果)
                3.创建MyCallable的对象(表示多线程要执行的任务)
                4.创建FutureTask的对象(作用管理多线程运行的结果)
                5.创建Thread类的对象,并启动(表示线程)

定义任务类,要实现Callable接口,实现接口中的 call() 方法

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int result = 0;
        System.out.println(Thread.currentThread().getName() + " Holle world");
        for (int i = 0; i < 15; i++) {
            result += i;
        }
        return result;
    }
}

创建FutureTask的对象,创建Thread类的对象,并启动

public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*多线程的第三种实现方式:
        特点:可以获取到多线程运行的结果
         */
        //创建MyCallable的对象(表示多线程要执行的任务)
        MyCallable mc = new MyCallable();
        //创建FutureTask的对象(作用管理多线程运行的结果)
        FutureTask<Integer> fu = new FutureTask<>(mc);
        FutureTask<Integer> fu1 = new FutureTask<>(mc);
        //创建线程的对象
        Thread t1 = new Thread(fu);
        Thread t2 = new Thread(fu1);
        t1.setName("线程1");
        t2.setName("线程2");
        //启动线程
        t1.start();
        t2.start();
        //获取多线程运行的结果
        Integer result1 = fu.get();
        Integer result2 = fu1.get();
        System.out.println(result1 + " : " + result2);
    }
}

1.4、三种实现方式的优缺点

方式

优点

缺点

继承Thread类

编程比较简单,可以直接使用Thread类中的方法

可以扩展性较差,不能再继承其他的类

实现Runnable接口

扩展性强,实现该接口的同时还可以继承其他的类

编程相对复杂,不能直接使用Thread类中的方法

实现ca1lable接口

2、多线程常用方法

方法名称

说明

String getName()

返回此线程的名称

int getId()

返回此线程的ID

void setName(String name)

设置线程的名字(构造方法也可以设置名字)

static Thread currentThread( )

获取当前线程的对象

static void sleep(long time)

让线程休眠指定的时间,单位为毫秒

setPriority(int newPriority)

设置线程的优先级

final int getPriority( )

获取线程的优先级

final void setDaemon(boolean on)

设置为守护线程

public static void yield( )

出让线程/礼让线程

public static void join( )

插入线程/插队线程

常用方法注意点:

String getName() 返回此线程的名称

void setName(string name) 设置线程的名字(构造方法也可以设置名字)

1、如果我们没有给线程设置名字,线程也是有默认的名字的,格式是Thread-X(X序号,从0开始的)

2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

static Thread currentThread() 获取当前线程的对象

当IVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程,他的作用就是去调用main方法,并执行里面的代码,在以前,我们写的所有的代码,其实都是运行在main线程当中

static void sleep(long time) 让线程休眠指定的时间,单位为毫秒

1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间

2、方法的参数:就表示睡眠的时间,单位毫秒,1 秒=1000毫秒

3、当时间到了之后,线程会自动的醒来,抢占到CUP后,继续执行下面的其他代码

注意:Java中的线程调度采用的是抢占式的,线程的优先级从1到10,线程的优先级越低抢占CUP的概率就越低,线程的优先级越高抢占CUP的概率就越高,不是说线程的优先级越高就一定能抢占到CUP的,这是一个概率问题,并不是绝对的

自定义线程两个线程

//自定义线程MyThread1
public class MyThread1 extends Thread{
    @Override
    public void run() {
        //书写线程要执行代码
        for (int i = 0; i < 15; i++) {
            System.out.println(getName() +"@"+ i);
        }
    }
}

//自定义线程MyThread2
public class MyThread2 extends Thread {
    @Override
    public void run() {
        //书写线程要执行代码
        for (int i = 0; i < 70; i++) {
            System.out.println(getName() +"@"+ i);
        }
    }
}

final void setDaemon(boolean on)方法演示

守护线程的应用场景,假设有两个人通过QQ在聊天,并且有文件在传输,这时候就会有两个线程,分别是:聊天(线程1)和传输文件(线程2),当聊天结束,即线程1被关闭了,传输文件自然也就要关闭了,所以线程2要被设置成守护线程

public class ThreadDemo1 {
    public static void main(String[] args) {
        /*
         * final void setDaemon(boolean on) 设置为守护线程
         * 提示:当其他的非守护线程执行完毕之后,守护线程会陆续结束
         * 通俗易懂:当女神线程结束了,那么备胎线程也没有存在的必要了
         */
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("主线程");
        t2.setName("守护线程");
        //把第二个线程设置为守护线程(备胎线程)
        t2.setDaemon(true);
        //启动线程
        t1.start();
        t2.start();
    }
}

从运行结果可看出,主线程执行完毕之后,守护线程就陆续结束了

java中线程的执行过程

        Java中的主线程是程序的入口点,通常是在main()方法中定义。当程序启动时,主线程会从main()方法开始执行。当主线程遇到创建和启动子线程的代码时,它会创建一个新的线程对象,并调用该线程对象的start()方法,以启动新的线程。子线程在自己的run()方法中定义要执行的任务。

        主线程和子线程之间的执行顺序取决于调度器的策略。调度器负责分配CPU时间给每个线程,以便它们能够交替执行。

        通常情况下,主线程会先执行main()方法中的代码,然后创建和启动子线程。子线程的执行顺序可能是不确定的,取决于操作系统和Java虚拟机的实现。主线程和子线程可以同时执行,互不干扰。

        需要注意的是,如果主线程在子线程之前结束,那么子线程可能无法执行完毕。为了确保子线程能够完成任务,可以使用join()方法,在主线程中调用该方法等待子线程执行完毕。

推荐:

【Java多线程】多线程的三种实现方式和多线程常用方法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136961604【Java多线程】多线程的三种实现方式和多线程常用方法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136961604【java基础】异常处理机制-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136581375?spm=1001.2014.3001.5501

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STL —— string(2)

本篇文章主要讲解string的用法。 目录 1. 迭代器&#xff08;Iterators&#xff09; 1.1 begin() 和 end() 1.2 rbegin() 和 rend() 2. 容量操作&#xff08;capacity&#xff09; 2.1 size()、length()、maxsize() 2.2 capacity() 2.3 empty()、clear() 2.4 reserve…

罗德与施瓦茨联合广和通全面验证RedCap模组FG132系列先进性能

近日&#xff0c;罗德与施瓦茨联合广和通完成Redcap(Reduce Capability)功能和性能验证。本次测试使用R&SCMX500 OBT(One Box Tester)无线通信测试仪&#xff0c;主要验证广和通RedCap模组FG132系列射频性能以及IP层吞吐量&#xff0c;包括RedCap上下行吞吐量和射频指标如矢…

【技巧】ChatGPT Prompt 提示语大全

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 主要来自&#xff1a;https://github.com/f/awesome-chatgpt-prompts ChatGPT SEO提示 Contributed by: StoryChief AI Reference: 7 Powerful ChatGPT Prompts to Create SEO Content Faster 供稿人&#xff1a;…

ruoyi-nbcio-plus基于vue3的flowable增加开始节点的表单绑定修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

Python文件读写操作

文件操作注意点 注意点&#xff1a; 1. for line in file --> 会将偏移量移到末尾 2. buffering1 --> 缓冲区中遇到换行就刷新&#xff0c;即向磁盘中写入 3. 读操作结束后&#xff0c;文本偏移量就会移动到读操作结束位置 """编写一个程序,循环不停的写入…

快速区分清楚图形渲染中的AABB,KD树和BVH这些概念

快速区分清楚图形渲染中的AABB&#xff0c;KD树和BVH这些概念 主要想形象去区分好这些术语&#xff0c;目的是扫盲&#xff0c;先开好坑&#xff0c;内容持续填充。 0.先摆出这些词的全称 AABB&#xff1a; 原名&#xff1a;axis aligned bounding box&#xff1b;中文直译名…

Java语法学习八之认识String类

String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可以使用标准库提供的字符串系列函数完成大部分操作&#xff0c;但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想&#xff0c;而…

高效的Gitlab Flow最佳实践

文章目录 一、git flow二、github flow三、gitlab flow四、基于gitlab flow的最佳实践1.语义化版本号2.测试发布3.bug修复 参考 业界包含三种flow&#xff1a; Git flowGithub flowGitlab flow 三种工作流程&#xff0c;有一个共同点&#xff1a;都采用"功能驱动式开发&…

计算机二级Python基础操作题

题目来源&#xff1a;计算机二级Python半个月抱佛脚大法&#xff08;内呈上真题版&#xff09; - 知乎 第4&#xff0c;5&#xff0c;6&#xff0c;7&#xff0c;9&#xff0c;10&#xff0c;11套 1. 基础题1 sinput() print("{:\"^30x}".format(eval(s))) b …

xilinx linux AXI GPIO 驱动学习

vivado工程 vivado 配置一个 AXI GPIO&#xff0c; 全输出&#xff0c;宽度为1 设备树解读 生成的对应pl.dtsi设备树文件如下 axi_gpio: gpio40020000 {#gpio-cells <2>;clock-names "s_axi_aclk";clocks <&clkc 15>;compatible "xlnx,…

海外盲盒App开发:探索惊喜与乐趣的跨国新体验

在全球化日益加速的今天&#xff0c;人们对新鲜、有趣、充满惊喜的体验需求不断增长。盲盒作为一种充满神秘与乐趣的玩法&#xff0c;正迅速在全球范围内走红。为了满足广大海外用户的盲盒体验需求&#xff0c;我们致力于开发一款海外盲盒App&#xff0c;为用户带来跨国界的惊喜…

C#,图论与图算法,计算无向连通图中长度为n环的算法与源代码

1 无向连通图中长度为n环 给定一个无向连通图和一个数n,计算图中长度为n的环的总数。长度为n的循环仅表示该循环包含n个顶点和n条边。我们必须统计存在的所有这样的环。 为了解决这个问题,可以有效地使用DFS(深度优先搜索)。使用DFS,我们可以找到特定源(或起点)的长度…

高精度AI火灾烟雾检测算法,助力打造更加安全的楼宇环境

一、方案背景 近日&#xff0c;南京居民楼火灾事故导致15人死亡的新闻闹得沸沸扬扬&#xff0c;这一事件又激起了大家对楼宇火灾隐患的进一步担忧。事后我们除了思考政府、消防及物业部门应对此事的解决办法&#xff0c;我们还应该思考如何利用现有的技术帮助人们减少此类事情的…

手撕算法-无重复字符的最长子串

描述 分析 滑动窗口&#xff0c;记录窗口中的所有出现的字符&#xff0c;然后窗口左边界固定&#xff0c;右边界右滑&#xff0c;如果&#xff0c;窗口中不存在新的字符&#xff0c;则右滑成功&#xff0c;否则左边界右滑&#xff0c;直到窗口中不存在右边界的值。 描述感觉不…

Linux初学(八)磁盘管理

一、磁盘管理 1.1 简介 磁盘的工作原理&#xff1a; 添加磁盘对磁盘进行分区格式化磁盘挂载和使用磁盘 磁盘的类型&#xff1a; 固态机械 磁盘的接口类型&#xff1a; IDESTSTSCSI 磁盘工作的原理&#xff1a; 磁盘&#xff0c;特别是硬盘&#xff0c;和内存不同&#xff0c;…

【网络基础】网络层基本协议介绍

目录 一、IP数据包 1.1 网络层的功能 1.2 IP数据包格式 二、ICMP协议介绍 2.1 作用 2.2 常用命令 2.2.1 Ping命令 2.2.2 tracert命令 2.3 广播域 三、ARP协议介绍 3.1 作用 3.2 原理 一、IP数据包 1.1 网络层的功能 定义了基于IP协议的逻辑地址&#xff0c;就是I…

IDEA使用手册

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

优化选址问题 | 基于禁忌搜索算法求解基站选址问题含Matlab源码

目录 问题代码问题 禁忌搜索算法(Tabu Search)是一种局部搜索算法的扩展,它通过引入一个禁忌列表来避免陷入局部最优解,并允许在一定程度上接受较差的解来跳出局部最优。在基站选址问题中,我们可以使用禁忌搜索算法来寻找满足覆盖要求且基站数量最少的选址方案。 以下是…

无人机采集图像的相关知识

1.飞行任务规划 一般使用飞行任务规划软件进行飞行任务的设计&#xff0c;软件可以自动计算相机覆盖和图像重叠情况。比如ArduPilot (ArduPilot - Versatile, Trusted, Open) 和UgCS (http://www.ugcs.com)是两个飞行任务规划软件&#xff0c;可以适用大多数无人机系统。 2.图…

Java 模拟Spring,实现IOC和AOP的核心(二)

接着上一篇&#xff0c;在上一篇完成了有关IOC的注解实现&#xff0c;这一篇用XML的方式实现IOC&#xff0c;并且完成AOP。 简易的IOC框图 注解的方式实现了左边的分支&#xff0c;那么就剩下右边的XML分支&#xff1a; XmlContext&#xff1a; 这个类是也是AbstractApplicat…