Java并发编程 | 创建线程的几种方式

文章目录

    • 一、简介
    • 二、使用Thread类创建线程
      • 2.1 继承Thread类
        • 2.1.1 创建Thread子类
        • 2.1.2 重写run方法
        • 2.1.3 启动线程的方式
          • 方式一:创建线程对象后调用start方法
          • 方式二:直接使用匿名内部类创建线程对象并调用start方法
      • 2.2 使用匿名内部类创建线程
      • 2.3 线程的生命周期和状态转换
    • 三、使用Runnable接口创建线程
      • 3.1 实现Runnable接口
        • 3.1.1 创建Runnable实现类
        • 3.1.2 实现run方法
      • 3.2 将Runnable实例传递给Thread对象
      • 3.3 与Thread类创建线程的比较
    • 四、使用Executor框架创建线程
      • 4.1 Executor框架概述
      • 4.2 使用ExecutorService接口
        • 4.2.1 创建ExecutorService实例
        • 4.2.2 提交任务和获取Future对象
        • 4.2.3 关闭ExecutorService
      • 4.3 线程池的优势和配置
    • 五、使用Callable和Future创建线程
      • 5.1 Callable接口概述
      • 5.2 创建Callable实现类
        • 5.2.1 实现call方法
      • 5.3 使用Future获取任务结果
        • 5.3.1 提交Callable任务
        • 5.3.2 获取Future对象
        • 5.3.3 处理任务结果和异常
    • 六、总结
      • 6.1 不同方式创建线程的比较
      • 6.2 选择合适的线程创建方式
      • 6.3 注意事项和常见问题




一、简介

  在并发编程中,线程是执行代码的基本单位。通过创建多个线程,可以实现并发执行,提高程序的效率和响应性。

  多线程编程具有以下优势:

  • 提高程序的运行效率和响应性。
  • 充分利用多核处理器的计算能力。
  • 实现并发任务的协作和通信。




二、使用Thread类创建线程


2.1 继承Thread类

2.1.1 创建Thread子类

  通过继承Thread类,可以创建自定义的线程类。

public class MyThread extends Thread {// 构造方法可以用于传递线程名称等参数public MyThread(String name) {super(name);}// 重写run方法,定义线程执行的代码逻辑@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + getName());}
}

2.1.2 重写run方法

  在创建Thread子类时,需要重写run方法,定义线程执行的代码逻辑。

public class MyThread extends Thread {@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + getName());}
}

2.1.3 启动线程的方式

  创建并启动线程的方式有两种:

方式一:创建线程对象后调用start方法
MyThread thread = new MyThread("线程1");
thread.start();
方式二:直接使用匿名内部类创建线程对象并调用start方法
Thread thread = new Thread("线程2") {@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + getName());}
};thread.start();

2.2 使用匿名内部类创建线程

  使用匿名内部类可以简化线程的创建过程。

Thread thread = new Thread() {@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + getName());}
};thread.start();

2.3 线程的生命周期和状态转换

  线程的生命周期包括新建、就绪、运行、阻塞和终止等状态。线程的状态可以通过调用Thread类的方法进行转换。

Thread thread = new Thread() {@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + getName());}
};// 启动线程
thread.start();// 阻塞线程
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}// 终止线程
thread.interrupt();




三、使用Runnable接口创建线程


3.1 实现Runnable接口

3.1.1 创建Runnable实现类

  通过实现Runnable接口,可以创建自定义的线程类。

public class MyRunnable implements Runnable {// 实现run方法,定义线程执行的代码逻辑@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + Thread.currentThread().getName());}
}

3.1.2 实现run方法

  在创建Runnable实现类时,需要实现run方法,定义线程执行的代码逻辑。

public class MyRunnable implements Runnable {@Overridepublic void run() {// 线程执行的代码逻辑System.out.println("线程执行中:" + Thread.currentThread().getName());}
}

3.2 将Runnable实例传递给Thread对象

  使用Runnable接口创建线程时,需要将实现了Runnable接口的实例传递给Thread对象。

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);// 启动线程
thread.start();

3.3 与Thread类创建线程的比较

  使用Runnable接口创建线程相比于继承Thread类创建线程,具有以下优势:

  • 避免单继承的限制:Java中,一个类只能继承一个父类,但可以实现多个接口。通过实现Runnable接口,可以灵活地在不同的类中复用线程代码。

  • 提高代码的可扩展性:将线程的执行逻辑与线程类解耦,可以更方便地对线程的执行逻辑进行修改和扩展。

  • 适合资源共享:多个线程可以共享同一个Runnable实例,从而实现对共享资源的访问和操作。

  使用Runnable接口创建线程是一种更加灵活和可扩展的方式,适用于多线程环境中的资源共享和代码复用。



四、使用Executor框架创建线程


4.1 Executor框架概述

  Executor框架是Java提供的用于管理和执行线程的高级工具。它通过将任务的提交和执行进行解耦,提供了更灵活、可控的线程管理方式。

4.2 使用ExecutorService接口

4.2.1 创建ExecutorService实例

  使用Executor框架创建线程的核心接口是ExecutorService。可以通过Executors类提供的静态方法来创建ExecutorService实例。

ExecutorService executorService = Executors.newFixedThreadPool(5);

  上述代码创建了一个固定大小为5的线程池。

4.2.2 提交任务和获取Future对象

  通过ExecutorService的submit方法可以提交任务,并返回一个表示任务结果的Future对象。

Future<String> future = executorService.submit(new Callable<String>() {@Overridepublic String call() throws Exception {// 任务执行的代码逻辑return "任务执行结果";}
});// 获取任务执行结果
try {String result = future.get();System.out.println("任务执行结果:" + result);
} catch (InterruptedException | ExecutionException e) {e.printStackTrace();
}

4.2.3 关闭ExecutorService

  在使用完ExecutorService后,应该及时关闭以释放资源。

executorService.shutdown();

  上述代码关闭了ExecutorService,不再接受新的任务提交,但会等待已提交的任务执行完成。

4.3 线程池的优势和配置

  使用线程池的优势包括:

  • 重用线程:线程池中的线程可以被重复利用,避免了线程的频繁创建和销毁,提高了线程的利用率。

  • 控制并发数:线程池可以限制并发执行的线程数,避免因线程过多导致系统资源耗尽的问题。

  • 提供任务队列:线程池可以提供一个任务队列,将未执行的任务暂存起来,等待线程空闲时执行。


  线程池的配置可以根据实际需求进行调整,常用的配置参数包括:

  • 核心线程数:线程池中始终保持的线程数量。

  • 最大线程数:线程池中允许的最大线程数量。

  • 任务队列:用于存放未执行的任务的队列。

  • 线程空闲时间:当线程空闲时间超过设定值时,多余的线程会被销毁。

  • 拒绝策略:当线程池无法接受新的任务时,如何处理新的任务。

  可以通过调用Executors类提供的方法来创建不同类型的线程池,并根据实际需求进行配置。




五、使用Callable和Future创建线程


5.1 Callable接口概述

  Callable接口是Java提供的一个用于表示可返回结果的任务的接口。与Runnable接口不同,Callable接口的call方法可以返回执行结果,并且可以抛出异常。

5.2 创建Callable实现类

5.2.1 实现call方法

  创建一个实现了Callable接口的类,并实现其call方法,定义任务的执行逻辑。

import java.util.concurrent.Callable;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {// 任务执行的代码逻辑return "任务执行结果";}
}

5.3 使用Future获取任务结果

5.3.1 提交Callable任务

  将实现了Callable接口的实例提交给ExecutorService来执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class Main {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(5);Future<String> future = executorService.submit(new MyCallable());}
}

5.3.2 获取Future对象

  通过submit方法返回的Future对象,可以获取任务的执行结果。

try {String result = future.get();System.out.println("任务执行结果:" + result);
} catch (InterruptedException | ExecutionException e) {e.printStackTrace();
}

5.3.3 处理任务结果和异常

  在获取任务结果时,可能会抛出InterruptedException和ExecutionException异常,需要进行相应的异常处理。

try {String result = future.get();System.out.println("任务执行结果:" + result);
} catch (InterruptedException e) {e.printStackTrace();
} catch (ExecutionException e) {e.printStackTrace();
}

  以上是使用Callable和Future创建线程的基本方法和处理任务结果和异常的示例。通过Callable接口和Future对象,可以实现具有返回结果的任务,并对任务的执行结果进行处理。




六、总结


6.1 不同方式创建线程的比较

  在Java中,有多种方式可以创建线程,包括继承Thread类、实现Runnable接口以及使用Callable和Future。这些方式各有特点,可以根据具体的需求选择合适的方式。

  • 继承Thread类:简单易用,但线程与任务耦合度较高,无法复用线程对象。
  • 实现Runnable接口:解耦了线程和任务,可以实现线程的复用,适合多个线程共享一个任务的场景。
  • 使用Callable和Future:可以获取任务的执行结果,并处理可能的异常,适合需要获取任务返回结果的场景。

6.2 选择合适的线程创建方式

  选择合适的线程创建方式取决于具体的需求和场景:

  • 如果只是简单地执行一个任务,且不需要获取任务的返回结果,可以考虑继承Thread类或实现Runnable接口。
  • 如果需要获取任务的返回结果,可以使用Callable和Future,通过Future对象获取任务的执行结果。
  • 如果需要多个线程共享一个任务,可以实现Runnable接口,并将任务对象传递给多个线程进行执行。

6.3 注意事项和常见问题

  在使用多线程时,需要注意以下事项和常见问题:

  • 线程安全:多个线程同时操作共享数据时可能出现线程安全问题,需要采取同步措施来保证数据的一致性。
  • 异常处理:在使用Callable和Future时,需要处理可能抛出的异常,以防止程序出现异常后无法正常执行。
  • 线程池的使用:使用线程池可以提高线程的复用性和管理性,避免频繁创建和销毁线程的开销。
  • 避免死锁:在多线程编程中,需要注意避免死锁情况的发生,合理设计锁的获取和释放顺序。

  合理选择线程创建方式,并注意处理线程安全和异常问题,可以更好地进行多线程编程。

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

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

相关文章

5.CSS(二)

目录 一、Emmet语法 &#xff08;一&#xff09;快速生成HTML结构语法 &#xff08;二&#xff09;快速生成CSS样式语法 二、CSS的复合选择器 &#xff08;一&#xff09;后代选择器&#xff08;重要&#xff09; &#xff08;二&#xff09;子选择器&#xff08;重要&…

自然语言处理从入门到应用——LangChain:模型(Models)-[聊天模型(Chat Models):使用少量示例和响应流式传输]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 使用少量示例 本部分的内容介绍了如何在聊天模型&#xff08;Chat Models&#xff09;中使用少量示例。关于如何最好地进行少量示例提示尚未形成明确的共识。因此&#xff0c;我们尚未固定任何关于此的抽象概念&#…

什么是Java中的JVM(Java虚拟机)?

JVM&#xff08;Java虚拟机&#xff09;是Java平台的核心组件之一&#xff0c;是一个用于执行Java字节码的虚拟计算机。Java源代码经过编译器编译&#xff0c;生成字节码文件&#xff08;.class文件&#xff09;&#xff0c;然后由JVM来解释和执行这些字节码。JVM负责将字节码翻…

kafka消息监听

1&#xff0c;spring配置kafka网址 2&#xff0c;listener Component public class OrderMsgListener {KafkaListener(topics "order",groupId "order-service")public void listen(ConsumerRecord record){System.out.println("收到消息&#xf…

Upload文件导入多条数据到输入框

需求场景&#xff1a;文本框内容支持批量导入(文件类型包括’.txt, .xls, .xlsx’)。使用AntD的Upload组件处理。 下面是Upload的配置&#xff08;伪代码&#xff09;&#xff0c;重点为beforeUpload中的逻辑 // Antd 中用到的Upload组件 import { UploadOutlined } from ant…

静态路由小实验

文章目录 一、实验要求及拓扑图二、实验步骤三、思考题 一、实验要求及拓扑图 二、实验步骤 1、创建VLAN&#xff0c;将端口划入vlan 在交换机S3、S4上创建VLAN10、20 Switch(config)#vl 10 Switch(config-vlan)#vl 20 S3(config)#int f0/3 S3(config-if)#switchport access …

vue3 实现排序按钮

需求背景解决效果index.vue 需求背景 需要实现一个复用性&#xff0c;是提供表单顺倒排序的按钮 解决效果 index.vue <!--/*** author: liuk* date: 2023/7/25* describe: 排序按钮*/--> <template><div class"sort-fn"><span :class"[…

一次线上OOM问题的个人复盘

我们一个java服务上线后&#xff0c;偶尔会发生内存OOM(Out Of Memory)问题&#xff0c;但由于OOM导致服务不响应请求&#xff0c;健康检查多次不通过&#xff0c;最后部署平台kill了java进程&#xff0c;这导致定位这次OOM问题也变得困难起来。 最终&#xff0c;在多次review代…

chrome 模拟发送POST请求和GET请求

F12打开Console输入以下代码&#xff1a; POST请求 var url "http://ip地址:8080/test/?id26323"; var params {"billIds":["56141305725718528"],"billType":"VBNSC"}; var xhr new XMLHttpRequest(); xhr.open(&quo…

kafka权限控制功能

参考链接&#xff1a; https://www.clougence.com/cc-doc/dataMigrationAndSync/database/privs_for_kafka Kafka需要的权限 | CloudCanal of ClouGence Kafka Topic 权限控制可以通过使用 Apache Kafka 的内置安全特性来实现。这主要涉及到两个方面&#xff1a;认证&#…

electron的electron-packager打包运行和electron-builder生产安装包过程,学透 Electron 自定义 Dock 图标

electron的electron-packager打包运行和electron-builder生产安装包过程 开发electron客户端程序&#xff0c;打包是绕不开的问题。 macOS 应用构建&#xff0c;看似近在咫尺&#xff0c;实则坑坑致命。 场景&#xff1a;mac笔记本打包&#xff0c;以及生产出可交付的软件安装…

什么是事件循环Event Loop

一、含义 事件循环是指不断从任务队列中取出任务&#xff0c;并执行其对应的回调函数的过程。 二、事件循环流程 1.主线程执行同步任务&#xff0c;直到遇到异步任务时&#xff0c;将其回调函数他家到任务队列中&#xff0c;然后继续执行同步任务 2.当所有同步任务执行完之后&a…

如何利用plotly和geopandas根据美国邮政编码(Zip-Code)绘制美国地图

对于我自己来说&#xff0c;该需求源自于分析Movielens-1m数据集的用户数据&#xff1a; UserID::Gender::Age::Occupation::Zip-code 1::F::1::10::48067 2::M::56::16::70072 3::M::25::15::55117 4::M::45::7::02460 5::M::25::20::55455 6::F::50::9::55117我希望根据Zip-…

驱动(分步注册驱动设备)

头文件 #ifndef __LED_H__ #define __LED_H__#define PHY_LED1_MODER 0X50006000 #define PHY_LED1_ODR 0X50006014 #define PHY_LED1_RCC 0X50000A28#define PHY_LED2_MODER 0X50007000 #define PHY_LED2_ODR 0X50007014 #define PHY_LED2_RCC 0X50000A28#define PHY_LED3…

在 3ds Max 和 After Effects 中创建逼真的蜘蛛网模型

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建蜘蛛网 步骤 1 打开 3ds Max。 打开 3ds Max 步骤 2 转到创建>标准基元>平面并创建一个平面 在前视图中。 创建平面 步骤 3 保持其长度和宽度 segs 为 80。 段 步骤 4 打开修改器列表…

生活杂记-显示器尺寸

以下是常见显示器尺寸的对角线长度换算成厘米的结果&#xff08;已经四舍五入到最接近的厘米数&#xff09;&#xff1a; 19英寸显示器 ≈ 48.26厘米21.5英寸显示器 ≈ 54.61厘米24英寸显示器 ≈ 60.96厘米27英寸显示器 ≈ 68.58厘米32英寸显示器 ≈ 81.28厘米34英寸显示器 ≈…

Python爬虫之Scrapy框架系列(23)——分布式爬虫scrapy_redis浅实战【XXTop250部分爬取】

目录&#xff1a; 1.实战讲解&#xff08;XXTop250完整信息的爬取&#xff09;&#xff1a;1.1 使用之前做的完整的XXTOP250项目&#xff0c;但是设置为只爬取一页&#xff08;共25个电影&#xff09;,便于观察1.2 配置settings文件中使用scrapy_redis的必要配置&#xff0c;并…

智能汽车的主动悬架工作原理详述

摘要&#xff1a; 本文将详细介绍主动悬架功能原理设计。 主动悬架是车辆上的一种汽车悬架。它使用车载系统来控制车轮相对于底盘或车身的垂直运动&#xff0c;而不是由大弹簧提供的被动悬架&#xff0c;后者的运动完全由路面决定。主动悬架分为两类&#xff1a;真正的主动悬架…

fSGAT批量候选基因关联分析丨快速单基因关联分析

候选基因如何分析&#xff1f; 通常情况下关联分析会得到一大堆候选基因&#xff0c;总不可能每个都有用&#xff0c;因此需要对候选基因进行深一步分析&#xff0c;本篇笔记分享一下群体遗传学研究中GWAS候选位点与候选基因的筛选思路。主要的方式包括单基因关联分析、连锁程度…

ubuntu 静态IP设置

ubuntu 静态IP设置&#xff1a; 1.输入&#xff1a; sudo vim /etc/netplan/01-network-manager-all.yaml Let NetworkManager manage all devices on this system network: ethernets: ens33: dhcp4: no addresses: [192.168.1.119/24] gateway4: 192.168.1.1 nameservers: …