多线程的实现方式

点击链接返回标题->

Java线程的学习-CSDN博客


第一种方式,继承Thread类

Thread类是java.lang包下的类,是多线程经常需要使用的类。

①通过自定义子类去继承Thread类,并重写其中的run()方法。

class myThread extends Thread {//自定义子类myThread继承Thread类

    @Override
    public void run() {//重写run()方法
        for (int i = 1; i <= 100; i++) {
            System.out.println(getName() + "打印了" + i);//
        }
    }
}

②用自定义子类实例化对象t,这个对象t就是一个线程,并调用对象t的start()方法,启动该线程。

myThread t1 = new myThread();//实例化对象,线程t1
myThread t2 = new myThread();//实例化对象,线程t2

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

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

③可以调用对象t的setName()方法,给线程命名,如果不命名,默认线程名为Thread-0、Thread-1...调用getName()方法获取当前线程名

t1.setName("线程1");//设置线程t1的名字
t2.setName("线程2");//设置线程t2的名字

示例代码——

public class Main {
    public static void main(String[] args) {
        myThread t1 = new myThread();//实例化对象,线程t1
        myThread t2 = new myThread();//实例化对象,线程t2

        t1.setName("线程1");//设置线程t1的名字
        t2.setName("线程2");//设置线程t2的名字

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

class myThread extends Thread {//自定义子类myThread继承Thread类

    @Override
    public void run() {//重写run()方法
        for (int i = 1; i <= 100; i++) {
            System.out.println(getName() + "打印了" + i);//
        }
    }
}

 这里展现出部分运行结果,可以看到,cpu在执行这段代码时,在线程1和线程2之间反复切换(执行线程1还是线程2,是随机的!)


 第二种方式,实现Runnable接口

Runnable接口是java.lang包下的接口

在大多数情况下,如果只打算重写run()方法而不使用其他Thread方法,则应使用Runnable接口

①通过自定义子类去实现Runnable接口,并重写其中的run()方法。

class MyRun implements Runnable {
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("MyThread类的run()方法在运行");
        }
    }
}

②用自定义子类实例化对象mr,这个mr现在还不是线程,而是线程要执行的任务。

MyRun mr = new MyRun();

③用Thread类实例化对象t,并传入mr实现有参构造,这个t才是线程,用start()方法启动线程。

//Thread类传入MyRun的对象通过有参构造实例化对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);

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

④同样的,可以调用对象t的setName()方法,给线程命名,但是——因为这个自定义子类是实现Runnable接口而不是继承Thread类,所以在自定义子类中不能直接调用Thread类的getName()方法获取线程名字。解决方法是,在这个自定义类中用Thread类中的一个静态方法Thread.currentThread(),获取当前线程的实例化对象,然后调用这个对象的方法。

class MyRun implements Runnable {
    public void run() {
        Thread th = Thread.currentThread();//获取当前线程的实例化对象
        for (int i = 1; i <= 100; i++) {
            System.out.println(th.getName() + "MyThread类的run()方法在运行");
        }
    }
}

示例代码——

public class Main {
    public static void main(String[] args) {
        MyRun mr = new MyRun();
        //Thread类传入MyRun的对象通过有参构造实例化对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        //设置线程名字
        t1.setName("线程1");
        t2.setName("线程2");

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

class MyRun implements Runnable {
    public void run() {
        Thread th = Thread.currentThread();//获取当前线程的实例化对象
        for (int i = 1; i <= 100; i++) {
            System.out.println(th.getName() + "MyThread类的run()方法在运行");
        }
    }
}

部分运行结果—— 


 第三种方式,实现Callable接口

我们发现前两种方式都是通过重写run()方法的形式来实现,但这个run()方法的返回值却是void类型的,也就是说,我们无法通过返回值获取多线程中的运行结果。

假如线程A执行一个运算任务,线程B需要获取线程A的运算结果,这该如何实现呢?

Callable接口是java.util.concurrent包下的接口,它的特点是可以获取到多线程运行的结果。

①通过自定义子类去实现Callable接口,并重写call()方法,call()方法必须声明抛出异常。

有关Java异常详见本篇->Java异常-CSDN博客

class mycall implements Callable<Integer> {//这个<Integer>是声明泛型的返回值是整数
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

②用自定义子类实例化对象mc,这个mc现在还不是线程,而是线程要执行的任务。

mycall mc = new mycall();

③用FutureTask类去实例化对象ft,这个对象用来管理线程的返回值

FutureTask<Integer> ft = new FutureTask<>(mc);

 ④用Thread类创建线程对象t,传入管理线程任务的对象ft实现有参构造,并调用对象t的start()方法启动线程。

Thread t1 = new Thread(ft);

Thread t2 = new Thread(ft);

t1.start();

t2.start();

⑤调用ft的get()方法获取对应线程的运行结果,这个结果可以作为数据按实际需求使用。

Integer res1 = ft.get();

Integer res2 = ft.get();

System.out.println(res1 + res2);

示例代码——

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

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {//此处方法需要注意声明抛出异常
        mycall mc = new mycall();
        FutureTask<Integer> ft = new FutureTask<>(mc);
        Thread t1 = new Thread(ft);
        Thread t2 = new Thread(ft);
        t1.start();
        t2.start();
        Integer res1 = ft.get();
        Integer res2 = ft.get();
        System.out.println(res1 + res2);
    }
}

class mycall implements Callable<Integer> {//这个<Integer>是声明泛型的返回值是整数

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}


三种方式的对比

对于后两种方式, 不能直接使用Thread类中的方法,解决方法为:先调用Thread类的静态方法currentThread(),获取当前线程的实例化对象,再用该实例化对象来调用需要使用的方法。


线程的常用成员方法将在下篇介绍,敬请期待!

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

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

相关文章

(5秒解决)ImportError: attempted relative import with no known parent package

寻找了很多方法&#xff0c;发现大家把事情讲的复杂了。我这里用最简单的办法来解决父包引用找不到的问题。 报错提示&#xff1a;ImportError: attempted relative import with no known parent package 先给大家看看我的目录结构&#xff0c;model.py和test目录在同一级。tra…

Ubuntu 23.10 服务器版本 ifconfig 查不到网卡 ip(已解决)

文章目录 1、问题描述2、 解决方案 1、问题描述 服务器&#xff1a;ubuntu 23.10 经常会遇到虚拟机添加仅主机网卡后&#xff0c;通过 ifconfig 无法获取其网卡 ip 2、 解决方案 修改网卡配置文件&#xff1a; # 进入网卡配置文件目录 cd /etc/netplan # 备份原始文件 cp …

C/C++ 递归指数型枚举

个人主页&#xff1a;仍有未知等待探索_C语言疑难,数据结构,小项目-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 目录 一、前言 二、递归指数型枚举 1、题目信息 题目描述 输入格式 输出格式 样例 提示 2、解析 3、代码 一、前言 之前进行枚举…

数据结构与算法编程题14

设计一个算法&#xff0c;通过一趟遍历在单链表中确定值最大的结点。 #include <iostream> using namespace std;typedef int Elemtype; #define ERROR 0; #define OK 1;typedef struct LNode {Elemtype data; //结点保存的数据struct LNode* next; //结构体指针…

优思学院|2024年质量管理的大趋势

2023年我们已经顺利度过了整年的大部分时间&#xff0c;2024年质量管理的趋势和问题在全球范围内都已经引起了关注&#xff0c;或者仍然是企业导航的首要任务。 1. 通货膨胀与质量管理 2023年&#xff0c;全球范围内通货膨胀和严峻的经济状况成为企业最关心的问题之一。尽管物…

BootStrap【表格二、基础表单、被支持的控件、表单状态】(二)-全面详解(学习总结---从入门到深化)

目录 表格二 表单_基础表单 表单_被支持的控件 表单_表单状态 表格二 紧缩表格 通过添加 .table-condensed 类可以让表格更加紧凑&#xff0c;单元格中的内补&#xff08;padding&#xff09;均会减半 <table class"table table-condensed table-bordered"…

C#语言高阶开发

目录 数据结构 集合 动态数组ArrayList 习题&#xff1a;声明一个Monster类&#xff0c;有一个Attack方法,用一个ArrayList去封装Monster的对象,装10个&#xff0c;遍历monster的list让他们释放攻击方法 哈希表HashTable 创建一个武器类&#xff0c;有一个属性叫做id,每个…

SeaTunnel及SeaTunnel Web部署指南(小白版)

现在你能搜索到的SeaTunnel的安装。部署基本都有坑&#xff0c;官网的文档也是见到到相当于没有&#xff0c;基本很难找到一个适合新手小白第一次上手就能成功安装部署的版本&#xff0c;于是就有了这个部署指南的分享&#xff0c;小主已经把可能遇到的坑都填过了&#xff0c;希…

android keylayout键值适配

1、通过getevent打印查看当前keyevent数字对应事件和物理码 2、dumpsys input 查看输入事件对应的 KeyLayoutFile: /system/usr/keylayout/Vendor_6080_Product_8060.kl 3、通过物理码修改键值映射&#xff0c;修改/system/usr/keylayout/目录下的文件

redis-cluster集群模式

Redis-cluster集群 1 Redis3.0引入的分布式存储方案 2集群由多个node节点组成,redis数据分布在节点之中,在集群之中分为主节点和从节点3集群模式当中,主从一一对应,数据写入和读取与主从模式一样&#xff0c;主负责写&#xff0c;从只能读4集群模式自带哨兵模式&#xff0c;可…

视频剪辑有妙招:批量置入封面,轻松提升视频效果

随着社交媒体的兴起&#xff0c;视频已经成为分享和交流的重要方式。无论是专业的内容创作者还是普通的社交媒体用户&#xff0c;都要在视频剪辑上下一番功夫&#xff0c;才能让视频更具吸引力。而一个吸引的封面往往能在一瞬间抓住眼球&#xff0c;提高点击率。还在因如何选择…

基于Mapmost Alpha工具快速搭建3D场景可视化大屏

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

h5如何使用navigateBack回退到微信小程序页面并携带参数

前言 在h5中使用navigateBack回退到微信小程序页面很常见&#xff0c;但是有一种交互需要在回退之后的页面可以得到通知&#xff0c;拿到标识之后&#xff0c;进行某些操作&#xff0c;这样的话&#xff0c;由于微信官方并没有直接提供这样的api&#xff0c;就需要我们开动脑筋…

【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 6

1、明明买了一个扫地机器人&#xff0c;可以通过以下指令控制机器人运动: F:向前走 10 个单位长度 L:原地左转 90 度 R:原地右转 90 度 机器人初始方向向右&#xff0c;需要按顺序执行以下那条指令&#xff0c;才能打扫完下图中的道路 A、F-L-F-R-F-F-R-F-L-F B、F-R-F-L-F-F…

如何搭建Zblog网站并通过内网穿透将个人博客发布到公网

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕…

virtualList 封装使用 虚拟列表 列表优化

虚拟列表 列表优化 virtualList 组件封装 virtualList 组件封装 本虚拟列表 要求一次性加载完所有数据 不适合分页 新建一个select.vue 组件页面 <template><div> <el-select transfer"true" :popper-append-to-body"true"popper-class…

redis-cluster集群(目的:高可用)

1、特点 集群由多个node节点组成&#xff0c;redis数据分布在这些节点中&#xff0c;在集群中分为主节点和从节点&#xff0c;一个主对应一个从&#xff0c;所有组的主从形成一个集群&#xff0c;每组的数据是独立的&#xff0c;并且集群自带哨兵模式 2、工作原理 集群模式中…

Android系统调试工具大全:解密adb、dumpsys、procrank等神器

Android系统调试工具大全&#xff1a;解密adb、dumpsys、procrank等神器 引言 Android开发中&#xff0c;调试是一个非常重要的环节&#xff0c;本文将介绍一些常用的Android系统调试工具&#xff0c;包括adb、logcat、procrank、dumpsys、dmesg、top、free、df、trace、pm、…

如何使用Google My Business来提升您的内容和SEO?

如果您的企业有实体店&#xff0c;那么使用Google My Business&#xff08;GMB&#xff09;来改善您的本地SEO并增强您的在线形象至关重要。Google My Business &#xff08;GMB&#xff09; 是 Google 提供的补充工具&#xff0c;使企业能够控制其在 Google 搜索和地图上的数字…

【数字化转型方法论读书笔记】-数据中台角色解读

一千个读者&#xff0c;就有一千个哈姆雷特。同样&#xff0c;数据中台对于企业内部不同角色的价值也不同&#xff0c;下面分别从董事长、CEO、 CTO/CIO、IT 架构师、数据分析师这 5 个角色的视角详细解读数据中台。 1、董事长视角下的数据中台 在数字经济时代&#xff0c;企业…