当前位置: 首页 > news >正文

Java实现多线程有几种方式(满分回答)

目录

    • JDK8 创建的线程的两种方式
      • orcle文档解释
      • 方式一:继承Thread类
      • 方式二:实现Runnable接口
      • 同时用两种的情况
    • 其他间接创建方式
      • Callable接口
      • 线程池

JDK8 创建的线程的两种方式

orcle文档解释

orcle文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html

image-20230222102145410

总结:

准确的讲,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式:

  • 方法一:实现Runnable接口的重写run方法,并把Runnable实例传给Thread类
  • 方法二∶重写Threadrun方法(继承Thread类)

(其他一些方式,究其根本都是间接的通过上面两种方式创建的)

方式一:继承Thread类

public static void main(String[] args) {System.out.println("主线程运行:" + Thread.currentThread().getName());Task1 task = new Task1();task.start();}static class Task1 extends Thread{@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11继承Thread实现多线程");}}}}
  • 自定义线程类继承Thread类

  • 重写run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

方式二:实现Runnable接口

public static void main(String[] args) {Task task = new Task();Thread thread  = new Thread(task);thread.start();}static class Task implements Runnable{@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11实现Runnable接口实现多线程");}}}
  • 定义MyRunnable类实现Runnable接口

  • 实现run()方法,编写线程执行体

  • 创建线程对象,调用start()方法启动线程

同时用两种的情况

public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("实现Runnable的run方法");}}){@Overridepublic void run() {System.out.println("匿名内部类,重写Thread类的run方法");}}.run();
}

结果:

匿名内部类,重写Thread类的run方法

分析:

这里使用的匿名内部类,在匿名内部类里面又重写了Thread类的run方法。创建Thread类的同时传入了Runnable对象,这时候Thread类的run已被重写,不再是原生方法的逻辑:执行传入task的run

image-20230211121531177

所以即便传入Runnable,也不会被执行。

其他间接创建方式

Callable接口

public static void main(String[] args) {Task task = new Task();FutureTask<Integer> ft = new FutureTask<>(task);Thread thread = new Thread(ft);thread.start();}static class Task implements Callable<Integer> {@Overridepublic Integer call() throws Exception {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11实现Callable接口实现多线程");}return 1;}
}

FutureTask实现了RunnableFuture接口,RunnableFuture继承了RunnableFuture接口。所以也是间接通过Runnable来创建的。

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  • 提交执行:Future result1 = ser.submit(t1);
  • 获取结果: boolean r1 = result1.get()
  • 关闭服务: ser.shutdownNow();

实现Runnable接口和Callable接口的区别

  • Runnable 接口不会返回结果,Callable 接口可以返回结果
  • Callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是runnable接口实现类中run方法的异常必须在内部处理,不能抛出

线程池

ThreadPoolExecutor类的execute方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AEKGtqyC-1677038180765)(Java%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%B1%87%E6%80%BB%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0.assets/image-20230222115102680.png)]

public void execute(Runnable command) {if (command == null)throw new NullPointerException();/** Proceed in 3 steps:** 1. If fewer than corePoolSize threads are running, try to* start a new thread with the given command as its first* task.  The call to addWorker atomically checks runState and* workerCount, and so prevents false alarms that would add* threads when it shouldn't, by returning false.** 2. If a task can be successfully queued, then we still need* to double-check whether we should have added a thread* (because existing ones died since last checking) or that* the pool shut down since entry into this method. So we* recheck state and if necessary roll back the enqueuing if* stopped, or start a new thread if there are none.** 3. If we cannot queue task, then we try to add a new* thread.  If it fails, we know we are shut down or saturated* and so reject the task.*/int c = ctl.get();//如果工作线程数小于核心线程数,if (workerCountOf(c) < corePoolSize) {//执行addWorker,会创建一个核心线程,如果创建失败,重新获取ctlif (addWorker(command, true))return;c = ctl.get();}//如果工作线程数大于等于核心线程数,线程池的状态是RUNNING,并且可以添加进队列//(RUNNING状态下)如果添加失败,说明是队列已经满了,接着就去创建新的线程,如果大于最大线程数,则执行拒绝策略//如果线程池不是RUNNING状态,则执行拒绝策略(当然还会调addWorker进行判断一次)if (isRunning(c) && workQueue.offer(command)) {//再次获取ctl,进行双重检索(也就是对线程池的状态再次检查一遍)int recheck = ctl.get();//如果线程池是不是处于RUNNING的状态,那么就会将任务从队列中移除,//如果移除失败,则会判断工作线程是否为0 ,如果过为0 就创建一个非核心线程//如果移除成功,就执行拒绝策略,因为线程池已经不可用了;if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))//线程池挂了或者大于最大线程数reject(command);
}

addWork方法会创建线程池内工作线程WorkerWorker这个线程,实现了Runnable接口,并持有一个线程thread,一个初始化的任务firstTask。thread是调用构造方法时通过ThreadFactory来创建的线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TG3ITFgx-1677038180766)(Java%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%B1%87%E6%80%BB%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0.assets/image-20230222113722589.png)]

ThreadFactory中也是Runnable创建线程的模式。

在这里插入图片描述

相关文章:

Java实现多线程有几种方式(满分回答)

目录JDK8 创建的线程的两种方式orcle文档解释方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runnable接口同时用两种的情况其他间接创建方式Callable接口线程池JDK8 创建的线程的两种方式 orcle文档解释 orcle文档&#xff1a;https://docs.oracle.com/javase/8/docs…...

实例4:树莓派GPIO控制舵机转动

实例4&#xff1a;树莓派GPIO控制舵机转动 实验目的 通过背景知识学习&#xff0c;了解舵机的外观及基本运动方式。了解四足机器人mini pupper腿部单个舵机的组成结构。通过GPIO对舵机进行转动控制&#xff0c;熟悉PWM。了解mini pupper舵机组的整体调零。 实验要求 使用Py…...

【音视频处理】为什么MP3不是无损音乐?音频参数详解,码率、采样率、音频帧、位深度、声道、编码格式的关系

大家好&#xff0c;欢迎来到停止重构的频道。上期我们讨论了视频的相关概念&#xff0c;本期我们讨论音频的相关概念。包括采样率、码率、单双声道、音频帧、编码格式等概念。这里先抛出一个关于无损音频的问题。为什么48KHz采样率的.mp3不是无损音乐 &#xff0c;而48KHz采样率…...

Linux 环境变量

Linux 环境变量能帮你提升 Linux shell 体验。很多程序和脚本都通过环境变量来获取系统信息、存储临时数据和配置信息。在 Linux 系统上有很多地方可以设置环境变量&#xff0c;了解去哪里设置相应的环境变量很重要。 认识环境变量 bash shell 用环境变量&#xff08;environme…...

从功能测试(点点点)到进阶自动化测试,实现薪资翻倍我只用了3个月时间

前言 从事测试工作已3年有余了&#xff0c;今天想聊一下自己刚入门时和现在的今昔对比&#xff0c;虽然现在也没什么成就&#xff0c;只能说笑谈一下自己的测试生涯&#xff0c;各位看官就当是茶余饭后的吐槽吧&#xff0c;另外也想写一写自己的职场感想&#xff0c;希望对刚开…...

aspnetcore 原生 DI 实现基于 key 的服务获取

你可能想通过一个字符串或者其他的类型来获取一个具体的服务实现&#xff0c;那么在 aspnetcore 原生的 MSDI 中&#xff0c;如何实现呢&#xff1f;本文将介绍如何通过自定义工厂来实现。我们现在恰好有基于 Json 和 MessagePack 的两种序列化器有一个接口是这样的publicinter…...

华为OD机试 -最大子矩阵和(Python) | 机试题+算法思路+考点+代码解析 【2023】

最大子矩阵和 题目 给定一个二维整数矩阵 要在这个矩阵中 选出一个子矩阵 使得这个子矩阵内所有的数字和尽量大 我们把这个子矩阵成为“和最大子矩阵” 子矩阵的选取原则,是原矩阵中一段相互连续的矩形区域 输入 输入的第一行包含两个整数N,M (1 <= N,M <= 10) 表示…...

C2驾照科一学习资料(1)

目录 记1分 记3分 记6分 记9分 记12分 你有不伤别人的教养 却缺少一种不被人伤的气场 若没人护你周全 就请善良中带点锋芒为自己保驾护航 这个世界你若好到毫无保留 对方就会坏到肆无忌惮 记1分 《道路交通安全违法行为记分管理办法》规定&#xff0c;机动车驾驶人有下列…...

4576: 移动数组元素

描述给定一个n个元素的一维数组&#xff0c;将下标从0到p的元素全部平移到数组尾部。输入第一行有两个正整数n和p&#xff08;2<n<100&#xff0c;0<p<n&#xff09;。第二行有n个整数&#xff0c;表示数组的各个元素。输出在一行中按顺序输出移动后的各个数组元素…...

字符串中<br>处理

需求&#xff1a; 后端返回的字符串中带有br换行符&#xff0c;前端需要处理行内及行尾的换行符。具体需求可分为以下两个&#xff1a; 若是字符串末尾有换行符&#xff0c;需要去掉。若是字符串内有换行符&#xff0c;有两种需求&#xff1a;①将换行符转换成逗号或其它符号&…...

大数据技术原理与应用介绍

大数据技术原理与应用 概述 大数据不仅仅是数据的“大量化”&#xff0c;而是包含“快速化”、“多样化”和“价值化”等多重属性。 两大核心技术&#xff1a;分布式存储和分布式处理 大数据计算模式 批处理计算流计算图计算查询分析计算 大数据具有数据量大、数据类型繁…...

【Python】序列与列表(列表元素的增删改查,求之,列表推导式、列表的拷贝)

一、序列序列的概念&#xff1a;按照某种顺序排列的数据类型就叫做序列&#xff0c;比如字符串&#xff0c;列表&#xff0c;元组&#xff0c;集合序列的共同点是都有下标&#xff0c;支持index()方法和count()&#xff0c;也支持切片处理(等同于字符串序列的切片处理)l1 [0, …...

update导致死锁

update delete 操作&#xff0c;如果走的索引&#xff0c;对索引和主键索引加行锁 如果没有走索引&#xff0c;锁整张表。 不开启事务&#xff0c;mysql本身也会加锁 一般MYSQL在执行CREATE,ALTER,INSERT等命令时会自动加锁 在对数据进行更新操作时 如果update没用到索引&…...

Java 集合 --- 如何遍历Map

Java 集合 --- 如何遍历MapMap的基本操作如何遍历MapType of HashMapMap没有继承Collection接口AbstractMap和AbstractCollection是平级关系 Map的基本操作 package map; import java.util.*; /*** This program demonstrates the use of a map with key type String and val…...

C#从值类型、引用类型到装箱和拆箱

上一篇文章讲了C#的值类型和引用类型&#xff0c;这里再来看看值类型和引用类型最直接的使用场景&#xff1a;装箱和拆箱。 一、基本概念 装箱&#xff1a;值类型转化为引用类型的过程。从托管堆中为新生成的引用类型对象分配内存,再把值类型的实例字段拷贝到托管堆上新对象的…...

Java中的逻辑运算符/移位运算符简单总结

前段时间刷到了力扣关于位运算的题&#xff0c;这里浅浅记录一下&#xff01; 1. 逻辑位运算 1.1 与 & &&#xff1a;按位与进行二进制计算&#xff0c;规则是同为1则为1&#xff0c;不同为0&#xff0c;具体如下&#xff1a; 0&00, 0&10, 1&00, 1&…...

活动预告 | GAIDC 全球人工智能开发者先锋大会

大会主题——“向光而行的 AI 开发者” 2023 全球人工智能开发者先锋大会&#xff08;GAIDC&#xff09; 由世界人工智能大会组委会、上海市经济和信息化委员会、上海市人才工作领导小组办公室及中国&#xff08;上海&#xff09;自由贸易试验区临港新片区管理委员会指导&…...

【Linux系统】认识操作系统和操作系统如何进行管理以及进程相关状态

进程概念1 认识冯诺依曼体系结构1.1 冯诺依曼体系结构存储器的作用2 操作系统(Operator System&#xff0c;OS)2.1 OS如何进行管理3 进程3.1 OS管理进程&#xff1a;先描述再组织3.2 描述进程-PCB3.3 查看进程3.4 通过系统调用获取进程标识符3.5 通过系统调用创建子进程——for…...

【0基础学爬虫】爬虫基础之HTTP协议的基本原理介绍

大数据时代&#xff0c;各行各业对数据采集的需求日益增多&#xff0c;网络爬虫的运用也更为广泛&#xff0c;越来越多的人开始学习网络爬虫这项技术&#xff0c;K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章&#xff0c;为实现从易到难全方位覆盖&#xff0c;特设【0基础学…...

SpringBoot 整合定时任务

注解概览 EnableScheduling 在配置类上使用&#xff0c;开启计划任务的支持&#xff08;类上&#xff09; Scheduled 来申明这是一个任务&#xff0c;包括cron,fixDelay,fixRate等类型&#xff08;方法上&#xff0c;需先开启计划任务的支持&#xff09; pom依赖 <parent…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...