Java多线程创建方式全解

Java多线程创建方式全解

在Java编程中,多线程是一个重要的概念,它能让程序同时执行多个任务,提高程序的效率和响应能力。以下将详细介绍Java中创建多线程的四种方式。

一、继承Thread类

(一)创建步骤

  1. 定义线程类
    创建一个类并继承自Thread类。在这个类中,重写run()方法,run()方法中的代码就是这个线程要执行的任务。例如:
class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("线程 " + getName() + " 执行,i = " + i);}}
}
  1. 创建并启动线程
    在主程序中创建线程对象,并调用start()方法来启动线程。start()方法会自动调用线程对象的run()方法,使得线程开始执行。例如:
public class ThreadExample {public static void main(String[] args) {MyThread thread1 = new MyThread();thread1.start();MyThread thread2 = new MyThread();thread2.start();}
}

(二)特点

这种方式简单直接,符合面向对象的编程思想。但是,由于Java是单继承的,如果一个类已经继承了其他类,就无法再继承Thread类来创建线程。

二、实现Runnable接口

(一)创建步骤

  1. 定义实现Runnable接口的类
    创建一个类实现Runnable接口,然后实现接口中的run()方法,将线程要执行的任务写在run()方法中。例如:
class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("线程 " + Thread.currentThread().getName() + " 执行,i = " + i);}}
}
  1. 创建并启动线程
    首先创建实现了Runnable接口的类的对象,然后将这个对象作为参数传递给Thread类的构造函数来创建线程对象,最后调用start()方法启动线程。例如:
public class RunnableExample {public static void main(String[] args) {MyRunnable runnable1 = new MyRunnable();Thread thread1 = new Thread(runnable1);thread1.start();MyRunnable runnable2 = new MyRunnable();Thread thread2 = new Thread(runnable2);thread2.start();}
}

(二)特点

这种方式避免了单继承的限制,因为一个类可以实现多个接口。同时,多个线程可以共享同一个Runnable对象,比较适合多个线程执行相同任务的情况。

三、使用Callable和Future接口(适用于有返回值的线程)

(一)创建步骤

  1. 定义实现Callable接口的类
    创建一个类实现Callable接口,需要指定返回值类型。实现call()方法,在这个方法中编写线程要执行的任务,并返回一个结果。例如,计算1到100的整数和:
import java.util.concurrent.Callable;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() {int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}return sum;}
}
  1. 创建并执行线程,获取结果
    通过ExecutorService来管理线程的执行。首先创建Callable对象,然后将其提交给ExecutorService,返回一个Future对象。通过Future对象可以获取线程执行后的返回值。例如:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class CallableExample {public static void main(String[] args) {MyCallable callable = new MyCallable();// 创建一个线程池,这里只使用一个线程来执行任务,实际可以根据需求调整线程数量ExecutorService executor = Executors.newSingleThreadExecutor();try {Future<Integer> future = executor.submit(callable);// 获取线程执行后的结果Integer result = future.get();System.out.println("计算结果为: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();} finally {// 关闭线程池executor.shutdown();}}
}

(二)特点

这种方式的优势在于可以获取线程执行后的返回值,并且可以通过ExecutorService来更好地管理线程,如设置线程池大小、控制线程的执行顺序等。但相比前两种方式,代码稍微复杂一些。

四、使用线程池创建多线程

(一)使用ExecutorServiceExecutors创建线程池

  1. 创建线程池
    可以使用Executors工厂类来创建不同类型的线程池。例如,创建一个固定大小的线程池:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 创建一个包含5个线程的固定大小线程池ExecutorService executorService = Executors.newFixedThreadPool(5);}
}

Executors还可以创建其他类型的线程池,如CachedThreadPool(根据需要创建线程,线程空闲一段时间后会被回收)、SingleThreadExecutor(只有一个线程的线程池)等。
2. 定义任务(可以是实现Runnable接口或Callable接口的类)
例如,定义一个实现Runnable接口的任务类:

class MyTask implements Runnable {@Overridepublic void run() {System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行任务");}
}
  1. 提交任务到线程池
    将任务提交给线程池执行。对于实现Runnable接口的任务,可以使用execute()方法提交;对于实现Callable接口的任务(用于有返回值的情况),可以使用submit()方法提交。以下是提交Runnable任务的示例:
public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(5);// 创建任务对象MyTask task = new MyTask();// 提交任务到线程池,这个任务会被线程池中的某个线程执行for (int i = 0; i < 10; i++) {executorService.execute(task);}// 关闭线程池,不再接受新任务,但会等待已提交的任务执行完毕executorService.shutdown();}
}
  1. 关闭线程池(可选)
    当任务都提交完毕后,可以关闭线程池。shutdown()方法会平滑地关闭线程池,它会等待所有已提交的任务执行完毕后再关闭线程池。如果希望立即关闭线程池,不等待未完成的任务,可以使用shutdownNow()方法,但这种方式可能会导致正在执行的任务被中断。

(二)自定义线程池(使用ThreadPoolExecutor

Executors工厂类提供的创建线程池的方法实际上是对ThreadPoolExecutor的封装。如果需要更精细地控制线程池的参数和行为,可以直接使用ThreadPoolExecutor来创建线程池。
ThreadPoolExecutor的构造函数有多个参数,其主要参数如下:

  • corePoolSize:核心线程数,即使线程池中的线程处于空闲状态,也会保留这些线程。
  • maximumPoolSize:线程池允许的最大线程数。
  • keepAliveTime:当线程数大于核心线程数时,多余线程的空闲存活时间。
  • unitkeepAliveTime的时间单位。
  • workQueue:用于存放等待执行任务的阻塞队列。
  • threadFactory:用于创建新线程的工厂。
  • handler:当线程池和队列都满了时,用于处理新任务的拒绝策略。

以下是一个自定义线程池的示例:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class CustomThreadPoolExample {public static void main(String[] args) {// 核心线程数为3int corePoolSize = 3;// 最大线程数为5int maximumPoolSize = 5;// 多余线程空闲存活时间为10秒long keepAliveTime = 10;TimeUnit unit = TimeUnit.SECONDS;// 创建阻塞队列用于存放任务BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, unit, workQueue);MyTask task = new MyTask();for (int i = 0; i < 10; i++) {try {threadPoolExecutor.execute(task);} catch (Exception e) {e.printStackTrace();}}// 关闭线程池threadPoolExecutor.shutdown();}
}

通过自定义线程池,可以根据具体的应用场景和性能要求,精确地调整线程池的参数,从而更好地控制线程的执行和资源的利用。

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

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

相关文章

Windows注册表基础学习

修改注册表让cmd ascii输出有颜色 reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1 如何打开注册表编辑器 运行regedit 按下"Winr"组合键&#xff0c;在打开的"运行"对话框中输入"regedit"&#xff0c;单击"确定"…

CarSim复制数据注意事项

更正&#xff0c;上图中提到的“数据集”应该是“数据类别”&#xff0c;可以理解为数据集的一个子集。

Spring:注解开发依赖注入

Spring为了使用注解简化开发&#xff0c;并没有提供构造函数注入、setter注入对应的注解&#xff0c;只提供了自动装配的注解实现。 直接上代码&#xff1a; 1&#xff0c;添加一个配置类SpringConfig Configuration ComponentScan("com.itheima") //PropertySourc…

springboot006基于SpringBoot的网上订餐系统(源码+包运行+LW+技术指导)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

【Linux】learning notes(2)

文章目录 1、快捷键2、专业名词2.1、驱动2.2、内核2.3、U-Boot2.4、Dynamic Library and Static Library2.5、SDK / NDK / UDK 3、BUG 前文链接&#xff1a; 【Linux】learning notes 1、快捷键 在文件夹里&#xff0c;ctrll&#xff0c;选定文件夹路径 Linux下的ctrl常用组合…

商业银行核心系统单元化改造的研究与思考

随着金融科技的快速发展&#xff0c;银行核心系统面临着更高的处理能力、扩展能力及业务连续性的要求与挑战。为应对这些挑战&#xff0c;许多银行开始考虑对其核心系统进行单元化改造。本文首先分析了传统银行核心系统存在的问题以及单元化改造的必要性&#xff0c;然后详细阐…

指针

内存和地址 内存 我们知道计算上CPU&#xff08;中央处理器&#xff09;在处理数据的时候&#xff0c;需要的数据是在内存中读取的&#xff0c;处理后的数据也会放回内存中&#xff0c;那我们电脑上的哪些内存空间如何高效的管理呢&#xff1f; 其实也是把内存划分为一个个的…

强大的正则表达式——Medium

由上一篇文章《Easy》中提到过的&#xff1a; 还是直接让AI写个python脚本生成难度2的正则表达式&#xff0c;但是生成的正则表达式无法成功获取到flag&#xff1a; 这里了解了一下相关知识&#xff0c;字符串形式的整数对常数求模是可以用有限状态机来实现的。对于二进制数字来…

科技改变工作方式:群晖NAS安装内网穿透实现个性化办公office文档分享(1)

文章目录 前言1. 本地环境配置2. 制作本地分享链接3. 制作公网访问链接4. 公网ip地址访问您的分享相册5. 制作固定公网访问链接 前言 本文将详细介绍如何在群晖NAS上安装Synology Office和Synology Drive Server&#xff0c;并利用Cpolar内网穿透工具为本地文档配置固定的公网…

android:taskAffinity 对Activity退出时跳转的影响

android:taskAffinity 对Activity跳转的影响 概述taskAffinity 的工作机制taskAffinity对 Activity 跳转的影响一个实际的开发问题总结参考 概述 在 Android 开发中&#xff0c;任务栈&#xff08;Task&#xff09;是一个核心概念。它决定了应用程序的 Activity 如何相互交互以…

运算放大器的学习(三)增益带宽积

我们接着了解运放的相关指标参数&#xff0c;下面我们看下增益带宽积与压摆率. 增益带宽积:即电压增益&#xff08;Gain&#xff09;和带宽&#xff08;Bandwidth&#xff09;的乘积是一个常数&#xff0c;称为增益带宽积&#xff08;Gain Bandwidth Product&#xff09;. 增益…

ThinkPHP6门面(Facade)

门面 门面&#xff08;Facade&#xff09; 门面为容器中的&#xff08;动态&#xff09;类提供了一个静态调用接口&#xff0c;相比于传统的静态方法调用&#xff0c; 带来了更好的可测试性和扩展性&#xff0c;你可以为任何的非静态类库定义一个facade类。 系统已经为大部分…

【概率论】概率密度到底是什么

1. 书本上的定义&#xff1a; 如果对于随机变量X的分布函数F(X)&#xff0c;存在一个非负可积函数f(x)&#xff0c;使得任意实数x&#xff0c;都有&#xff1a; 称X为连续型随机变量&#xff0c;函数f(x)称为X的概率密度 所谓的概率密度&#xff0c;就是 概率/区间长度 &#…

线代笔记期末复习

第一讲行列式的计算 基础定义和规则 ps&#xff1a; 交换时不止行可以交换&#xff0c;列方便时也可以 我的第一作法&#xff1a;是把行相加&#xff0c;然后后续无差别 范德蒙行列式的计算&#xff1a; 要求第一行/列全为1 每个公比元素作差再相乘 爪型 步骤&#xff1a;…

javaweb快速入门 - 01

1.基本概念 web开发&#xff1a; web&#xff0c;网页的意思 &#xff0c; www.baidu.com静态web html&#xff0c;css提供给所有人看的数据始终不会发生变化&#xff01; 动态web 淘宝&#xff0c;几乎是所有的网站&#xff1b;提供给所有人看的数据始终会发生变化&#xf…

计算机网络学习笔记-6.应用层

文章目录 客户端-服务器模型&#xff08;C/S&#xff09;对等网络模型&#xff08;P2P&#xff09;DNS&#xff08;域名系统&#xff09;文件传输协议&#xff08;FTP&#xff09;FTP的基本功能&#xff1a;FTP的工作原理&#xff1a; 万维网&#xff08;WWW&#xff09;URL万维…

使用IDE实现java端远程调试功能

使用IDE实现java端远程调试功能 1. 整体描述2. 前期准备3. 具体操作3.1 修改启动命令3.2 IDE配置3.3 打断点3.4 运行Debug 4. 总结 1. 整体描述 在做项目时&#xff0c;有些时候&#xff0c;需要和第三方进行调式&#xff0c;但是第三方不在一起&#xff0c;需要进行远程调试&…

241118学习日志——[CSDIY] [InternStudio] 大模型训练营 [07]

CSDIY&#xff1a;这是一个非科班学生的努力之路&#xff0c;从今天开始这个系列会长期更新&#xff0c;&#xff08;最好做到日更&#xff09;&#xff0c;我会慢慢把自己目前对CS的努力逐一上传&#xff0c;帮助那些和我一样有着梦想的玩家取得胜利&#xff01;&#xff01;&…

简单爬虫的实现

以下是一个简单爬虫代码的实现&#xff1a; import requests from bs4 import BeautifulSoup# 生成一个包含多个网页 URL 的列表 # 这里我们构造了 50 个页面的 URL&#xff0c;假设网站有多页内容&#xff0c;页数从 1 到 50 urls [f"https://www.cnblogs.com/#p{i}&qu…

RNN简单理解;为什么出现Transformer:传统RNN的问题;Attention(注意力机制)和Self-Attention(自注意力机制)区别;

目录 RNN简单理解 RNN n to n Transformer N to M LSTM 为什么出现Transformer:传统RNN的问题 信息丢失的后果 Rnn是顺序执行的效率不高:顺序执行 Attention(注意力机制)和Self-Attention(自注意力机制)区别 一、计算对象不同 二、应用场景不同 三、功能差异…