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

014_多线程

多线程

  • 多线程
  • 创建线程
    • 方式一:继承Thread类
    • 方式二:实现Runable接口
    • 方式三:实现Callbale接口
  • Thread的常用方法
  • 线程安全
  • 线程同步
    • 方式一:同步代码块
    • 同步方法
    • 方式三:Lock锁
  • 线性池
    • 创建线程池
    • 处理Runnable任务
    • 处理Callable任务
    • 通过Executors创建线程池
  • 并发/并行
    • 并发
    • 并行

多线程

  • 线程(Thread)是一个程序内部的一条执行流程。
  • 程序中如果只有一条执行流程,那这个程序就是单线程的程序。
  • 多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)。

创建线程

  • 启动线程必须是调用start方法,不是调用run方法。
    • 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行
    • 只有调用start方法才是启动一个新的线程执行。
  • 不要把主线程任务放在启动子线程之前。
    • 这样主线程一直是先跑完的,相当于是一个单线程的效果了。

方式一:继承Thread类

  • 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
  • 创建MyThread类的对象
  • 调用线程对象的start()方法启动线程(启动后还是执行run方法的)
  • 优缺点
    • 优点:编码简单
    • 缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。

方式二:实现Runable接口

  • 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
  • 创建MyRunnable任务对象
  • 把MyRunnable任务对象交给Thread处理。
  • 调用线程对象的start()方法启动线程
  • 优缺点
    • 优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
    • 缺点:需要多一个Runnable对象。
Thread****类提供的构造器说明
public Thread(Runnable target)封装Runnable对象成为线程对象
  • 匿名内部类写法
    • 可以创建Runnable的匿名内部类对象。
    • 再交给Thread线程对象。
    • 再调用线程对象的start()启动线程。

方式三:实现Callbale接口

  • 创建任务对象
    • 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
    • 把Callable类型的对象封装成FutureTask(线程任务对象)。
  • 把线程任务对象交给Thread对象。
  • 调用Thread对象的start方法启动线程。
  • 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果。
  • 优缺点
    • 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
    • 缺点:编码复杂一点。
  • FutureTask的API
FutureTask提供的构造器说明
public FutureTask<>(Callable call)把Callable对象封装成FutureTask对象。
FutureTask提供的方法说明
public V get() throws Exception获取线程执行call方法返回的结果。

Thread的常用方法

Thread提供的常用方法说明
public void run()线程的任务方法
public void start()启动线程
public String getName()获取当前线程的名称,线程名称默认是Thread-索引
public void setName (String name)为线程设置名称
public static Thread currentThread ()获取当前执行的线程对象
public static void sleep(long time)让当前执行的线程休眠多少毫秒后,再继续执行
public final void join()…让调用当前这个方法的线程先执行完!
Thread 提供的常见构造器说明
public Thread(String name)可以为当前线程指定名称
public Thread(Runnable target)封装Runnable对象成为线程对象
public Thread(Runnable target, String name)封装Runnable对象成为线程对象,并指定线程名称

线程安全

  • 多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。
    • 存在多个线程在同时执行
    • 同时访问一个共享资源
    • 存在修改该共享资源

线程同步

  • 线程同步是线程安全问题的解决方案。
  • 线程同步的核心思想
    • 让多个线程先后依次访问共享资源,这样就可以避免出现线程安全问题。
  • 线程同步的常见方案
    • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来。

方式一:同步代码块

  • 作用:把访问共享资源的核心代码给上锁,以此保证线程安全。
    • 对出现问题的核心代码使用synchronized进行加锁
    • 每次只能一个线程占锁进入访问
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行。
  • 对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug。
  • 锁对象的使用规范
    • 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
    • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
synchronized(同步锁) {访问共享资源的核心代码
}

同步方法

  • 作用:把访问共享资源的核心方法给上锁,以此保证线程安全。

  • 原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

  • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。

  • 如果方法是实例方法:同步方法默认用this作为的锁对象。

  • 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。

修饰符 synchronized 返回值类型 方法名称(形参列表) {操作共享资源的代码
}

方式三:Lock锁

  • Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。
  • Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
  • 锁对象建议使用final修饰,防止被别人篡改
  • 释放锁建议将释放锁的操作放到finally代码块中,确保锁用完了一定会被释放

线性池

  • 线程池就是一个可以复用线程的技术。
  • 不使用线性池的问题
    • 用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的, 创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
  • 线程池的工作原理
    线程池的基本概念是,在应用程序启动时创建一定数量的线程,并将它们保存在线程池中。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。当任务执行完毕后,线程将返回到线程池,可以被其他任务复用。
    • 线程池:{有限的任务队列(WorkQueue)}
    • 工作线程WorkThread进行选择任务队列的对象。
    • 任务接口
      • Runable
      • Callable

创建线程池

  • JDK 5.0起提供了代表线程池的接口:ExecutorService。
  • 方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
    ExecutorService ——> ThreadPoolExecutor
    • 通过ThreadPoolExecutor创建线程池。
      • 参数一:corePoolSize : 指定线程池的核心线程的数量。
      • 参数二:maximumPoolSize:指定线程池的最大线程数量。
      • 参数三:keepAliveTime :指定临时线程的存活时间。
      • 参数四:unit:指定临时线程存活的时间单位(秒、分、时、天)
      • 参数五:workQueue:指定线程池的任务队列。
      • 参数六:threadFactory:指定线程池的线程工厂。
      • 参数七:handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)
ThreadPoolExecutor类提供的构造器作用
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)使用指定的初始化参数创建一个新的线程池对象
  • 方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。

处理Runnable任务

  • ExecutorService的常用方法
方法名称说明
void execute(Runnable command)执行 Runnable 任务
Future submit(Callable task)执行 Callable 任务,返回未来任务对象,用于获取线程返回的结果
void shutdown()等全部任务执行完毕后,再关闭线程池!
List shutdownNow()立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的任务
  • 线程池的注意事项
    • 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
      什么时候会拒绝新任务?
    • 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
  • 任务拒绝策略
策略说明
ThreadPoolExecutor.AbortPolicy()丢弃任务并抛出RejectedExecutionException异常。是默认的策略
ThreadPoolExecutor. DiscardPolicy()丢弃任务,但是不抛出异常,这是不推荐的做法
ThreadPoolExecutor. DiscardOldestPolicy()抛弃队列中等待最久的任务 然后把当前任务加入队列中
ThreadPoolExecutor. CallerRunsPolicy()由主线程负责调用任务的run()方法从而绕过线程池直接执行

处理Callable任务

  • 线程池使用ExecutorService的方法处理Callable任务,并得到任务执行完后返回的结果。
    Future<T> submit(Callable<T> command)

通过Executors创建线程池

  • Executors是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。
  • 方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
方法名称说明
public static ExecutorService newFixedThreadPool(int nThreads)创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorService newSingleThreadExecutor()创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
public static ExecutorService newCachedThreadPool()线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60s则会被回收掉。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。
  • Executors不是适合做大型互联网场景的线程池方案。
    • 建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。

并发/并行

  • 正在运行的程序(软件)就是一个独立的进程。
  • 线程是属于进程的,一个进程中可以同时运行很多个线程。
  • 进程中的多个线程其实是并发和并行执行的。

并发

  • 进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发。

并行

  • 在同一个时刻上,同时有多个线程在被CPU调度执行。

相关文章:

014_多线程

多线程 多线程创建线程方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runable接口方式三&#xff1a;实现Callbale接口 Thread的常用方法线程安全线程同步方式一&#xff1a;同步代码块同步方法方式三&#xff1a;Lock锁 线性池创建线程池处理Runnable任务处理Callable…...

R语言基础包可视化(一:axis函数)

R语言基础包可视化(一:axis函数) 背景axis函数(坐标轴函数)各参数的图片示例hadj和padjline和poslty,lwd,lwd.ticksgap.axis总结背景 之前在介绍正态Q-Q图的过程中,画过标准正态分布的随机数、分数数、分布函数、密度函数的图像,相关的文章连接参考此处:R语言正态Q-Q图…...

Spring MVC 处理 HTTP 状态码、响应头和异常的完整示例

Spring MVC 处理 HTTP 状态码、响应头和异常的完整示例 1. 正常响应处理 通过 ResponseEntity 可以灵活控制 HTTP 状态码、响应头和响应体。 代码示例&#xff1a;创建资源返回 201 并设置 Location 头 import org.springframework.http.HttpHeaders; import org.springfram…...

Linux安装postgresql17

1、下载 wget https://ftp.postgresql.org/pub/source/v17.4/postgresql-17.4.tar.gz 2、上传解压 tar -zxvf postgresql-17.4.tar.gz 3、安装依赖 yum install -y perl-ExtUtils-Embed readline-devel zlib-devel pam-devel libxml2-devel libxslt-devel openldap-devel …...

从零搭建微服务项目Pro(第0章——微服务项目脚手架搭建)

前言&#xff1a; 在本专栏Base第0章曾介绍一种入门级的微服务项目搭建&#xff0c;尽管后续基于此框架上实现了Nacos、Eureka服务注册发现、配置管理、Feign调用、网关模块、OSS文件存储、JSR参数校验、LogBack日志配置&#xff0c;鉴权模块、定时任务模块等&#xff0c;但由于…...

dolphinscheduler创建文件夹显示存储未启用的问题--已解决

只要修改api-server/comf/common.properties和standalone-server/conf/common.properties里面的内容就可以了&#xff0c;应为你要靠standalone-server这个服务启动dolphinscheduler-web&#xff0c;其他就算怎么改你重启dolphinscheduler的时候系统也不会识别新的common.prope…...

C++线段树详解与实现技巧

📚 C++线段树详解与实现技巧 线段树(Segment Tree)是一种高效处理 区间查询 和 区间更新 的数据结构,时间复杂度为 O(log n)。本文结合代码实例,详解其核心原理与实现细节。 🌳 线段树结构特点 完全二叉树:使用数组存储,父子节点关系通过下标计算。区间划分:每个节…...

聊一聊原子操作和弱内存序

1、原子操作概念 在并发编程中&#xff0c;原子操作&#xff08;Atomic Operation&#xff09;是实现线程安全的基础机制之一。从宏观上看&#xff0c;原子操作是“不可中断”的单元&#xff0c;但若深入微观层面&#xff0c;其本质是由底层处理器提供的一组特殊指令来保证其原…...

VIRT, RES,SHR之间的关系

VIRT、RES 和 SHR 是进程内存使用的三个关键指标&#xff0c;它们之间的关系反映了进程的内存分配和使用情况。以下是它们的定义和关系&#xff1a; VIRT&#xff08;虚拟内存&#xff09;&#xff1a;表示进程分配的虚拟内存总量&#xff0c;包括所有代码、数据、共享库、堆栈…...

Ubuntu中部署MeloTTS

0. 环境 ubuntu server 22.04 cuda version 12.4 python version 3.9 1. 安装python依赖 git clone https://github.com/myshell-ai/MeloTTS.git cd MeloTTS注意不是执行 pip install melotts 如果国内服务器无法从github中下载源码&#xff0c;那么可以把github改为gitc…...

2024年React最新高频面试题及核心考点解析,涵盖基础、进阶和新特性,助你高效备战

以下是2024年React最新高频面试题及核心考点解析&#xff0c;涵盖基础、进阶和新特性&#xff0c;助你高效备战&#xff1a; 一、基础篇 React虚拟DOM原理及Diff算法优化策略 • 必考点&#xff1a;虚拟DOM树对比&#xff08;同级比较、Key的作用、组件类型判断&#xff09; •…...

Adobe After Effects的插件--------Optical Flares之Options概述

Optical Flares插件的Options是对整个效果的组装和设置。点击该按钮会弹出一个组装室弹窗。 Options组装室就是对每个【镜头对象】进行加工处理,再将其组装在一起,拼凑成完整的光效。 接下来是我对组装室的探索: 面板 面板中有预览、堆栈、编辑和浏览按钮,其作用是调节窗…...

深入解读 React 纯组件(PureComponent)

什么是纯组件&#xff1f; React 的纯组件(PureComponent)是 React.Component 的一个变体&#xff0c;它通过浅比较(shallow comparison)props 和 state 来自动实现 shouldComponentUpdate() 方法&#xff0c;从而优化性能。 核心特点 1. 自动浅比较&#xff1a; PureCompon…...

微信小程序事件详解

微信小程序中的事件绑定是实现交互功能的核心机制之一。通过事件绑定&#xff0c;开发者可以监听用户的操作行为&#xff08;如点击、输入、滑动等&#xff09;&#xff0c;并根据需要执行相应的逻辑处理。 以下是关于微信小程序事件绑定的详细说明&#xff1a; 一、事件绑定的…...

字符串与相应函数(上)

字符串处理函数分类 求字符串长度&#xff1a;strlen长度不受限制的字符串函数&#xff1a;strcpy,strcat,strcmp长度受限制的字符串函数:strncpy,strncat,strncmp字符串查找&#xff1a;strstr,strtok错误信息报告&#xff1a;strerror字符操作&#xff0c;内存操作函数&…...

Laravel源码进阶

Laravel源码进阶 版本 laravel5.8 生成服务容器 public index.php //compose必要操作 require __DIR__./../vendor/autoload.php; //容器文件 $app require_once __DIR__./../bootstrap/app.php;-bootstrap/app.php //初始化容器 构造函数中执行这个几个方法 //$this->…...

镜舟科技亮相 2025 中国移动云智算大会,展示数据湖仓一体创新方案

4月10-11日&#xff0c;2025 中国移动云智算大会在苏州金鸡湖国际会议中心成功举办。大会以“由云向智&#xff0c;共绘算网新生态”为主题&#xff0c;汇聚了众多行业领袖与技术专家&#xff0c;共同探讨了算力网络与人工智能的深度融合与未来发展趋势。 作为中国领先的企业级…...

2025蓝桥杯省赛C/C++研究生组游记

前言 至少半年没写算法题了&#xff0c;手生了不少&#xff0c;由于python写太多导致行末老是忘记打分号&#xff0c;printf老是忘记写f&#xff0c;for和if的括号也老是忘写&#xff0c;差点连&&和||都忘记了。 题目都是回忆版本&#xff0c;可能有不准确的地方。 …...

重读《人件》Peopleware -(6)Ⅰ管理人力资源Ⅴ-帕金森定律重探 Parkinson’s Law Revisited

1954年&#xff0c;英国作家C. Northcote Parkinson引入了一个概念&#xff1a;工作会膨胀以填满分配给它的时间&#xff0c;这个概念现在被熟知为帕金森定律。如果你不知道很少有管理者接受过任何管理培训的话&#xff0c;你可能会以为他们都参加过一个关于帕金森定律及其影响…...

Linux-内核驱动-led

登记设备号&#xff08;后面可以动态分配&#xff09; 自己定义内核函数 登记设备名字和功能 exit和init在内核启动自动执行 这样定义直接操作物理地址 ioctl 定义了设备文件的各种操作&#xff0c;并准备将其注册到内核中。 代码中声明了一个cdev结构体变量cdev&#xff0c;这…...

记录一次因ASM磁盘组空间不足,导致MAP进程无法启动

生产中 ADG 库出现告警,检查发现 map 进程异常: 检查 alter 日志,出现: ORA-19504:failed to create file "DATAC1/casarch/2_162186_1067953047.arc" ORA-17502:ksfdcre:4 Failed to create file ... ORA-15041:diskgroup "DATAC1" space exhausted OR…...

可能存在特殊情况,比如控制台显示有延迟、缓冲问题等影响了显示顺序。

从控制台输出看&#xff0c;正常逻辑应是先执行 System.out.println(" 未处理异常演示 "); 输出对应文本&#xff0c;再因 arr 为 null 访问 length 触发 NullPointerException 输出异常信息。可能存在特殊情况&#xff0c;比如控制台显示有延迟、缓冲问题等影响…...

使用DaemonSet部署集群守护进程集

使用DaemonSet部署集群守护进程集 文章目录 使用DaemonSet部署集群守护进程集[toc]一、使用DaemonSet部署日志收集守护进程集二、管理DaemonSet部署的集群守护进程集1.对DaemonSet执行滚动更新操作2.对DaemonSet执行回滚操作3.删除DaemonSet 一、使用DaemonSet部署日志收集守护…...

c++中继承方面的知识点

继承的概念及定义 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保 持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象 程序设计的层次结…...

PyTorch 学习笔记

环境&#xff1a;python3.8 PyTorch2.4.1cpu PyCharm 参考链接&#xff1a; 快速入门 — PyTorch 教程 2.6.0cu124 文档 PyTorch 文档 — PyTorch 2.4 文档 快速入门 导入库 import torch from torch import nn from torch.utils.data import DataLoader from torchvision …...

Spring AI 结构化输出详解

一、Spring AI 结构化输出的定义与核心概念 Spring AI 提供了一种强大的功能&#xff0c;允许开发者将大型语言模型&#xff08;LLM&#xff09;的输出从字符串转换为结构化格式&#xff0c;如 JSON、XML 或 Java 对象。这种结构化输出能力对于依赖可靠解析输出值的下游应用程…...

spring security oauth2.0的四种模式

OAuth 2.0 定义了 4 种授权模式&#xff08;Grant Type&#xff09;&#xff0c;用于不同场景下的令牌获取。以下是每种模式的详细说明、适用场景和对比&#xff1a; 一、授权码模式&#xff08;Authorization Code Grant&#xff09; 适用场景 • Web 应用&#xff08;有后端…...

从零开始的C++编程 2(类和对象下)

目录 1.构造函数初始化列表 2.类型转换 3.static成员 4.友元 5.内部类 6.匿名对象 1.构造函数初始化列表 ①之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅式&#xff0c;就是初始化列表&#xff0c;初始化…...

Vue 项目中 package.json 文件的深度解析

Vue 项目中 package.json 文件的深度解析 在 Vue 项目中&#xff0c;package.json 文件是项目配置的核心&#xff0c;它管理着项目的依赖关系、脚本命令、版本信息等重要内容。正确理解和配置 package.json 文件&#xff0c;对于项目的开发、构建、测试和部署都至关重要。本文…...

将三维非平面点集拆分为平面面片的MATLAB实现

将三维非平面点集拆分为平面面片的MATLAB实现 要将三维空间中不在同一平面上的点集拆分为多个平面面片&#xff0c;可以采用以下几种方法&#xff1a; 1. 三角剖分法 (Delaunay Triangulation) 最简单的方法是将点集进行三角剖分&#xff0c;因为三个点总是共面的&#xff1…...