Java进阶篇--创建线程的四种方式

news2024/11/15 11:09:36

目录

继承Thread类

扩展小知识:

Thread类的常见方法

Thread 类的静态方法

实现Runnable接口

使用Callable和Future创建线程

使用Executor框架创建线程池


继承Thread类

  1. 创建一个继承自Thread类的子类,并重写其run()方法,将相关逻辑实现,run()方法就是线程要执行的业务逻辑方法。
  2. 创建自定义的线程子类对象
  3. 调用子类实例的star()方法来启动线程

为了更好地理解单线程和多线程的执行过程,接下来通过一个图例分析一下单线程和多线程的区别。

从上图可以看出,单线程的程序在运行时,会按照代码的调用顺序执行,而在多线程中,main()方法和MyThread类的run()方法却可以同时运行,互不影响,这正是单线程和多线程的区别。

示例代码如下:

class MyThread extends Thread {
    public void run() {
        // 线程执行的代码逻辑
        System.out.println(Thread.currentThread().getName() +"线程正在运行");
    }
}
public class Main {
    public static void main(String[] args) {
        // 创建线程并启动
        MyThread thread = new MyThread();
        thread.start();
        System.out.println(Thread.currentThread().getName() + " main()方法执行结束");
    }
}

运行结果:

main main()方法执行结束
Thread-0线程正在运行

扩展小知识:

Thread类的常见方法

  1. start(): 启动线程,并使其进入可运行状态,当CPU调度到该线程时,会自动调用其run()方法开始执行线程代码。
  2. run(): 线程的执行逻辑,通常需要在子类中重写该方法以定义具体的线程行为。通过调用start()方法来启动线程时,系统会自动调用该方法。
  3. sleep(long millis): 让当前线程暂停执行指定的时间(以毫秒为单位),进入阻塞状态。暂停期间不占用CPU时间,其他线程可以继续执行。
  4. join(): 当一个线程A调用另一个线程B的join()方法时,线程A将会等待线程B执行完毕后才继续执行。
  5. getName(): 获取线程的名称。
  6. setName(String name): 设置线程的名称。
  7. getId(): 获取线程的唯一标识符。
  8. isAlive(): 判断线程是否存活,即线程是否已启动但尚未终止。
  9. setPriority(int priority): 设置线程的优先级,优先级范围为1-10,默认为5。优先级较高的线程在竞争资源时有更大的概率优先执行。
  10. yield(): 暂停当前正在执行的线程,并让出CPU资源给其他具有相同优先级的线程。仅是一种建议,不保证有效,具体是否产生效果取决于系统的调度器。
  11. interrupt(): 中断线程,给线程发送中断信号。线程在合适的时候可以检查到该中断请求,然后自行决定如何响应。
  12. isInterrupted(): 判断线程是否被中断,返回布尔值。
  13. static boolean interrupted(): 判断当前线程是否被中断,并清除中断状态。

Thread 类的静态方法

currentThread() 是 Thread 类的静态方法,它返回当前正在执行的线程对象。具体来说,它返回一个表示当前线程的 Thread 对象。

可以使用 Thread.currentThread() 来获取当前线程的引用。这个方法常用于需要获得当前执行线程对象的场景,例如需要在运行时获取线程的名称、线程优先级、判断线程是否被中断等操作。

注意:currentThread() 是 Thread 类的静态方法,因此可以直接通过 Thread.currentThread() 的方式调用,不需要创建 Thread 对象实例。

下面是一个示例代码,演示如何使用 currentThread() 方法:

public class Main {
    public static void main(String[] args) {
        // 获取当前线程对象
        Thread currentThread = Thread.currentThread();

        // 获取当前线程的名称
        String threadName = currentThread.getName();
        System.out.println("当前线程名称:" + threadName);//当前线程名称:main

        // 获取当前线程的优先级
        int threadPriority = currentThread.getPriority();
        System.out.println("当前线程优先级:" + threadPriority);//当前线程优先级:5

        // 判断当前线程是否被中断
        boolean isInterrupted = currentThread.interrupted();
        System.out.println("当前线程是否被中断:" + isInterrupted);//当前线程是否被中断:false
    }
}

注意:getPriority() 方法是 Thread 类的实例方法,用于获取线程的优先级。该方法返回一个表示线程优先级的整数值。

线程优先级的范围是从 1 到 10,默认优先级为 5。较大的优先级值意味着线程更重要或更紧急,但并不保证高优先级的线程总是比低优先级的线程先执行。

实现Runnable接口

  1. 创建一个类实现Runnable接口,并重写其run()方法。
  2. 然后创建Thread对象,并将该实现Runnable接口的类的实例作为参数传递给Thread构造函数。
  3. 最后调用Thread对象的start()方法启动线程。

注意,实现 Runnable 接口相比直接继承 Thread 类具有更好的灵活性和可扩展性,因为它允许多个线程共享相同的 Runnable 实例。

下面是一个实现 Runnable 接口的示例代码:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 在此处添加想要线程执行的代码逻辑
        System.out.println("线程运行中");
    }
}
public class Main {
    public static void main(String[] args) {
        // 创建 MyRunnable 实例
        MyRunnable myRunnable = new MyRunnable();

        // 创建 Thread 对象并传入 MyRunnable 实例
        Thread thread = new Thread(myRunnable);

        // 启动线程
        thread.start();
    }
}

使用Callable和Future创建线程

  1. 创建一个实现Callable接口的类,并重写其call()方法。
  2. 然后使用ExecutorService提交Callable任务,并通过Future对象获取返回结果。

注意:使用 Callable 和 Future 创建线程相比直接使用 Runnable 接口和 Thread 类更为灵活,因为它允许获得线程的执行结果,并能够异步地处理任务。

下面是使用 Callable 和 Future 创建线程的示例代码: 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Main implements Callable<String> {
    @Override
    public String call() {
        // 在此处添加想要线程执行的代码逻辑
        return "线程运行结束";
    }

    public static void main(String[] args) throws Exception {
        // 创建 CallableExample 实例
        Main callableExample = new Main();

        // 创建线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // 提交 CallableExample 实例到线程池并返回 Future 对象
        Future<String> future = executor.submit(callableExample);

        // 关闭线程池(可选)
        executor.shutdown();

        // 获取线程执行结果
        String result = future.get();
        System.out.println("线程结果: " + result);//线程结果: 线程运行结束

    }
}

使用Executor框架创建线程池

Executors提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

主要有newFixedThreadPool,newCachedThreadPool,newSingleThreadExecutor,newScheduledThreadPool。

注意,调用 shutdown() 方法后,线程池将不再接受新的任务,并且会等待已提交的任务执行完成。

使用 Executor 框架可以更方便地管理和控制线程池,避免手动创建和启动线程的繁琐操作。

下面是使用 Executor 框架创建线程池的示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
        // 创建固定大小的线程池,最多同时执行两个线程
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 提交任务到线程池
        executor.submit(new MyTask("任务1"));
        executor.submit(new MyTask("任务2"));
        executor.submit(new MyTask("任务3"));

        // 关闭线程池
        executor.shutdown();
    }

    static class MyTask implements Runnable {
        private String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("任务 " + name + " 正在执行");
        }
    }
}

执行结果

任务 任务2 正在执行
任务 任务1 正在执行
任务 任务3 正在执行

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

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

相关文章

Flink CDC数据同步

背景 随着信息化程度的不断提高&#xff0c;企业内部系统的数量和复杂度不断增加&#xff0c;因此&#xff0c;数据库系统的同步问题已成为越来越重要的问题。 缓存失效 在缓存中缓存的条目(entry)在源头被更改或者被删除的时候立即让缓存中的条目失效。如果缓存在一个独立的…

“返璞归真,数字排毒”,放下智能手机,美国功能手机卷土重来

近年来&#xff0c;智能手机的普及已经改变了人们的生活方式和沟通方式。然而&#xff0c;随着科技的不断进步和不断涌现的各种新应用程序&#xff0c;一些年轻人开始感到疲惫和厌倦。他们觉得智能手机带来了太多的干扰和依赖&#xff0c;也让人们容易沉迷于社交媒体和短视频。…

Rabbitmq的Federation Exchange

(broker 北京 ) &#xff0c; (broker 深圳 ) 彼此之间相距甚远&#xff0c;网络延迟是一个不得不面对的问题。有一个在北京的业务(Client 北京 ) 需要连接 (broker 北京 ) &#xff0c;向其中的交换器 exchangeA 发送消息&#xff0c;此时的网络延迟很小&#xff0c;(C…

全球边缘计算大会的十大至暗时刻

来源网友X小缘 ① 背景板文字全球边缘计算大会&#xff0c;被广告公司改为全球边缘计算机大会&#xff0c;因为他觉得少了个机字&#xff1b; ② 明天开会&#xff0c;今天遇到恶劣天气&#xff0c;讲师主持人一整晚滞留外地机场&#xff1b; ③ 视频直播的时候声音通道没开&am…

Redis数据结构全解析【超详细万字分析】

文章目录 前言一、SDS1、SDS的必要性2、SDS的数据结构3、SDS的优势O&#xff08;1&#xff09;复杂度获取字符串长度二进制安全不会发生缓冲区溢出节省空间 二、链表1、结构设计2、优缺点 三、压缩列表1、结构设计2、连续更新3、压缩列表的缺陷 四、哈希表1、结构设计2、哈希冲…

236. 二叉树的最近公共祖先-优化

本期我们对该题进行优化&#xff0c;不知道题目的小伙伴建议先看看之前的 236. 二叉树的最近公共祖先_KLZUQ的博客-CSDN博客 我们要将时间复杂度优化为O(N) class Solution { public:bool FindPath(TreeNode* root, TreeNode* x,stack<TreeNode*>& path){if(rootnul…

Kubernetes(K8s)基本环境部署

此处只做学习使用&#xff0c;配置单master环境。 一、环境准备 1、ip主机规划&#xff08;准备五台新机&#xff09;>修改各个节点的主机名 注意&#xff1a;关闭防火墙与selinux 节点主机名ip身份joshua1 kubernetes-master.openlab.cn 192.168.134.151masterjoshua2k…

无涯教程-分类算法 - 朴素贝叶斯

朴素贝叶斯算法是一种基于应用贝叶斯定理的分类技术&#xff0c;其中强烈假设所有预测变量彼​​此独立。简而言之&#xff0c;假设是某个类中某个要素的存在独立于同一类中其他任何要素的存在。 在贝叶斯分类中&#xff0c;主要的兴趣是找到后验概率&#xff0c;即给定某些观…

抽象类和接口有什么区别?

在 Java 中&#xff0c;抽象类和接口是两种不同的类类型。它们都不能直接实例化&#xff0c;并且它们都是用来定义一些基本的属性和方法的&#xff0c;但它们有以下几点不同&#xff1a; 定义不同&#xff1a;定义的关键字不同&#xff0c;抽象类是 abstract&#xff0c;而接口…

Linux操作系统--包管理yum

1.概述 YUM(全称为 Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 CentOS中的 Shell 前端软件包管理器。基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。…

软考:中级软件设计师:数据库并发控制,完整性约束,数据库安全

软考&#xff1a;中级软件设计师:数据库并发控制 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的…

CrossOver 23 新功能介绍 CrossOver 23 版本更新了哪些功能

本次发布的CrossOver 23为用户带来了许多令人期待的新功能和优化&#xff0c;特别是对游戏方面的支持&#xff0c;更是让广大Mac游戏玩家兴奋。CrossOver 23包括对Wine 8.0.1的更新&#xff0c;带来了5000多处改动&#xff0c;对各种应用程序进行了改进。该版本还包括 Wine Mon…

AD9361配置采用纯PL方式,QT编写的小软件可以快速实现

采用ADI官方的API函数&#xff0c;虽然能够快速的实现AD9361配置&#xff0c;让我们不必关注9361的内部寄存器的配置过程&#xff0c;但是在实际的项目开发过程中&#xff0c;也在一定程度上限制了AD9361与PL之间数据交互的灵活性。 今天给大家推荐采用AD9361官方提供的配置软…

Linux操作系统--克隆虚拟机

1.概述 我们在搭建大数据或者是集群的过程中,需要使用到许多配置相同或者相类似的环境。这一个时候就需要使用到克隆虚拟机的功能。 2.克隆虚拟机过程 (1).从现有虚拟机(关机状态)克隆出新虚拟机,右键选择管理=>克隆,如下所示 (2).直接点击下一步。如下所示 (3).选择…

什么是浮动(float)?请解释清楚浮动对父元素和兄弟元素的影响。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 浮动&#xff08;Float&#xff09;⭐ 浮动对父元素的影响⭐ 浮动对兄弟元素的影响⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入…

Centos8的NAT网络设置

1、先将虚拟机设置为NAT模式 2、打开虚拟网络编辑器&#xff0c;记录以下信息 NAT设置&#xff1a;子网掩码、网关 DHCP设置&#xff1a;I P 范围 (自动时) 3、进入Centos8的网络设置页面&#xff0c;按照记录的信息进行配置 4、重载、重启网卡 nmcli c reload ensl60 n…

什么是字体图标(Icon Font)?如何在网页中使用字体图标?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 字体图标&#xff08;Icon Font&#xff09;⭐ 如何在网页中使用字体图标⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&a…

Linux操作系统--常用指令(系统定时任务)

(1).概述 在实际的运维过程中,这一个功能使用的还是很多,比如,我们需要在定点的时候进行系统的备份、清理、存盘等工作。这一个时候就需要使用系统定时任务。 (2).查看crontab是否开启 (3). crontab 定时任务设置 功能:设置定时的任务 语法: crontab [选项] 选项: -e 编…

《向量数据库指南》——什么叫“AI 向量数据库”,它和我们日常理解的数据库有什么不同?

我认为"AI 向量数据库"这个概念非常切合实际,它类似于关系数据库在交易领域的作用。个人观点是,向量数据库实际上是为了人工智能而生的。一方面,向量数据库的数据完全源自于人工智能技术。另一方面,对于 AI 应用而言,向量数据库也是至关重要的基础设施。 至于…

【CSS】CSS 背景设置 ( 背景半透明设置 )

一、背景半透明设置 1、语法说明 背景半透明设置 可以 使用 rgba 颜色值设置半透明背景 ; 下面的 CSS 样式中 , 就是 设置黑色背景 , 透明度为 20% ; background: rgba(0, 0, 0, 0.2);颜色的透明度 alpha 取值范围是 0 ~ 1 之间 , 在使用时 , 可以 省略 0.x 前面的 0 , 直接…