Java基础——多线程

1. 线程

  1. 是一个程序内部的一条执行流程
  2. 程序中如果只有一条执行流程,那这个程序就是单线程的程序

2. 多线程

  1. 指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)

2.1. 如何创建多条线程

  1. Java通过java.lang.Thread类的对象来代表线程
2.1.1. 方式一:继承Thread类
// 1. 继承Thread类
public class MyThread extends Thread{// 2. 重写run方法@Overridepublic void run() {System.out.println("子线程");}
}
public static void main(String[] args) {// 3. 创建子线程对象Thread t = new MyThread();// 4. 启动子线程t.start();System.out.println("主线程");
}
  1. 优点:编码简单
  2. 缺点:已经继承Thread,无法继承其他类,不利于功能的扩展
  3. 启动线程必须调用start方法,而不能调用run方法,否则会将线程对象当作一个普通的对象。
  4. 不要把主线程任务放在启动子线程之前。
2.1.2. 方式二:实现Runnable接口
// 1. 定义任务类, 实现Runnable接口
public class MyRunnable implements Runnable {// 2. 重写run方法@Overridepublic void run() {System.out.println("Runnable子线程");}
}
public static void main(String[] args) {// 3. 创建一个任务对象Runnable runnable = new MyRunnable();// 4. 把任务对象交给一个线程对象, 启动线程new Thread(runnable).start();System.out.println("主线程");
}
  1. 任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强
2.1.3. 方式三:利用Callable接口、FutureTask类实现
  1. 以上两种方式的问题:如果线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。
  2. 使用Callable接口,可以返回线程执行完毕后的结果

  1. 未来任务对象的作用,是一个任务对象,实现了Runnable接口;可以在线程执行完毕之后,用未来任务对象调用get方法获取执行完的返回结果
// 1. 实现Callable接口
public class MyCallable implements Callable<String> {// 2. 重写call方法@Overridepublic String call() throws Exception {// 描述线程任务, 返回线程执行后的结果int sum = 0;for(int i = 1; i <= 100; i++){sum += i;}return String.valueOf(sum);}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {// 3. 创建一个Callable对象Callable<String> callable = new MyCallable();// 4. 将Callable对象封装成FutureTask任务对象FutureTask<String> futureTask = new FutureTask<>(callable);// 5. 使用任务对象创建一个线程对象, 并启动new Thread(futureTask).start();// 6. 获取线程执行完毕返回的结果String s = futureTask.get();System.out.println(s);
}

2.2. Thread的常用方法

3. 线程安全

  1. 多个线程,同时访问同一共享资源,且存在修改该资源的时候,可能会出现业务安全问题

4. 线程同步

  1. 是用于解决线程安全问题的方案
  2. 让多个线程实现先后依次访问共享资源,这样就解决了安全问题

4.1. 线程同步的方案

  1. 加锁,每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程再加锁进来。

4.2. 加锁的方式

4.2.1. 方式一:同步代码块
  1. 作用:把访问共享资源的核心代码块给上锁,以此保证线程安全
  2. 写法

  1. 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
  2. 注意事项:对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象)
  3. Ctrl + ALT + T选第九个,快速生成同步代码块
  4. 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象;静态方法建议使用字节码(类名.class)对象作为锁对象
4.2.2. 方式二:同步方法
  1. 作用:把访问共享资源的核心方法给上锁,以此保证线程安全。

  1. 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
4.2.3. 方式三:Lock锁
  1. 可以通过它创建锁对象,进行加锁和解锁
  2. Lock是接口,不能直接实例化,可以采用他的实现类ReentrantLock来创建锁对象。

5. 线程通信

  1. 当多个线程共同操作共享资源时,线程间通过某种方式互相告知自己的状态,一相互协调,并避免无效的资源争夺
  2. 生产者消费者问题

上述方法应该使用当前同步锁对象进行调用

public class Test5 {public static void main(String[] args) {// 有三个生产者线程负责生产包子, 每次只能有一个包子放在桌子上// 两个消费者线程负责吃包子, 每次只有一个线程能将包子吃掉// 1. 创建一个桌子对象Desk desk = new Desk();// 2. 创建三个厨师线程new Thread(() ->{while (true) {desk.put(); // 抢桌子}}, "厨师1").start();new Thread(() ->{while (true) {desk.put(); // 抢桌子}}, "厨师2").start();new Thread(() ->{while (true) {desk.put(); // 抢桌子}}, "厨师3").start();// 3. 创建两个吃货线程new Thread(() -> {while (true){desk.get();}},"吃货1").start();new Thread(() -> {while (true){desk.get();}},"吃货2").start();}
}
public class Desk {private List<String> list = new ArrayList<>();public synchronized void put() {try {String name = Thread.currentThread().getName();if(list.size() == 0){list.add(name + "包的包子");System.out.println(name + "包了一个包子");Thread.sleep(2000);// 唤醒别人, 等待自己this.notifyAll();this.wait();}else {  // 有包子了// 唤醒别人, 等待自己this.notifyAll();this.wait();}}catch (Exception e){e.printStackTrace();}}public synchronized void get() {try {if(list.size() == 1){ // 有包子String name = Thread.currentThread().getName();System.out.println(name + "吃了" + list.get(0));list.clear(); // 清空Thread.sleep(1000);// 唤醒别人, 等待自己this.notifyAll();this.wait();} else {// 唤醒别人, 等待自己this.notifyAll();this.wait();}}catch (InterruptedException e) {throw new RuntimeException(e);}}
}

6. 线程池

  1. 线程池就是一个可以复用线程的技术
  2. 代表线程池的接口,ExecutorService

6.1. 创建线程池对象

6.1.1. 使用ExecutorService的实现类ThreadPoolExecutor创建线程池对象

// 通过ThreadPoolExecutor创建一个线程池对象
/*
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 8,TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

注意事项:

  1. 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程
  2. 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务
  3. 如果是计算密集型任务,核心线程数 = CPU核数 + 1
  4. 如果是IO密集型任务,核心线程数 = CPU核数 * 2
6.1.2. 使用Executors(线程池工具类)调用静态方法返回不同特点的线程池对象

  1. 这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象
  2. 大型并发系统环境中使用Executors如果不注意可能会出现系统风险

6.2. 线程池处理Runnable任务、Callable任务

7. 并发、并行、线程的生命周期

7.1. 进程

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

7.2. 并发

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

7.3. 并行

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

7.4. 线程的生命周期

线程从创建到销毁的过程中,经历的各种状态及状态的转换

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

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

相关文章

使用Redis的一些经验总结

目录 一、Redis中的key和value的设计 1.key的命名规范 2.避免出现BigKey 3.value中选择恰当的数据类型 例1&#xff1a;比如存储一个User对象&#xff0c;我们有三种存储方式&#xff1a; ①方式一&#xff1a;json字符串 ②方式二&#xff1a;字段打散 ③方式三&#x…

如何在 Ubuntu 上配置 Kotlin 应用环境 ?

Kotlin 是一种运行在 Java 虚拟机 (JVM) 上的现代编程语言&#xff0c;它同时支持函数式和面向对象编程。它可与 Java 互操作&#xff0c;并以其简洁的语法而闻名。在本指南中&#xff0c;我们将介绍在 Ubuntu 系统上准备好 Kotlin 开发环境的要点&#xff0c;包括 Java、Kotli…

2024强化学习的结构化剪枝模型RL-Pruner原理及实践

[2024] RL-Pruner: Structured Pruning Using Reinforcement Learning for CNN Compression and Acceleration 目录 [2024] RL-Pruner: Structured Pruning Using Reinforcement Learning for CNN Compression and Acceleration一、论文说明二、原理三、实验与分析1、环境配置在…

嵌入式硬件电子电路设计(五)MOS管详解(NMOS、PMOS、三极管跟mos管的区别)

引言&#xff1a;在我们的日常使用中&#xff0c;MOS就是个纯粹的电子开关&#xff0c;虽然MOS管也有放大作用&#xff0c;但是几乎用不到&#xff0c;只用它的开关作用&#xff0c;一般的电机驱动&#xff0c;开关电源&#xff0c;逆变器等大功率设备&#xff0c;全部使用MOS管…

蓝桥杯每日真题 - 第14天

题目&#xff1a;&#xff08;2022&#xff09; 题目描述&#xff08;13届 C&C B组A题&#xff09; 解题思路&#xff1a; 定义状态&#xff1a; 使用一个二维数组 dp[j][k] 来表示将数字 k 拆分为 j 个不同正整数的方案数。 初始化&#xff1a; 初始状态设定为 dp[0][0]…

利用云计算实现高效的数据备份与恢复策略

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 利用云计算实现高效的数据备份与恢复策略 利用云计算实现高效的数据备份与恢复策略 利用云计算实现高效的数据备份与恢复策略 引…

thinkphp6配置多应用项目及多域名访问路由app配置

这里写一写TP6下配置多应用。TP6默认是单应用模式&#xff08;单模块&#xff09;&#xff0c;而我们实际项目中往往是多应用的&#xff08;多个模块&#xff09;&#xff0c;所以在利用TP6是就需要进行配置&#xff0c;开启多应用模式。 1、安装ThinkPHP6 1.1安装ThinkPHP6.…

JavaScript:浏览器对象模型BOM

BOM介绍 浏览器对象模型&#xff08;Brower Object Model&#xff0c;BOM&#xff09;提供了独立于内容而与浏览器窗口进行交互的对象&#xff0c;其核心对象是window BOM由一系列相关的对象构成&#xff0c;并且每个对象都提供了很多方法和属性。 BOM与DOM区别 DOM是文档对…

SpringBoot 2.2.10 无法执行Test单元测试

很早之前的项目今天clone现在&#xff0c;想执行一个业务订单的检查&#xff0c;该检查的代码放在test单元测试中&#xff0c;启动也是好好的&#xff0c;当点击对应的方法执行Test的时候就报错 tip&#xff1a;已添加spring-boot-test-starter 所以本身就引入了junit5的库 No…

前后端、网关、协议方面补充

这里写目录标题 前后端接口文档简介前后端视角对于前端对于后端代码注册路由路由处理函数 关于httpGET/POST底层网络关于前端的获取 路由器网关路由器的IP简介公网IP(WAN IP)私网IP(LAN IP)无线网络IP(WIFI IP)查询路由器私网IP路由器公网IP LAN口与WIFI简介基本原理 手动配置电…

英伟达基于Mistral 7B开发新一代Embedding模型——NV-Embed-v2

我们介绍的 NV-Embed-v2 是一种通用嵌入模型&#xff0c;它在大规模文本嵌入基准&#xff08;MTEB 基准&#xff09;&#xff08;截至 2024 年 8 月 30 日&#xff09;的 56 项文本嵌入任务中以 72.31 的高分排名第一。此外&#xff0c;它还在检索子类别中排名第一&#xff08;…

【计算机网络】TCP网络特点2

断开连接 四次挥手 原因 TCP 四次挥手是为了满足 TCP 连接的全双工特性:两个方向都可以自由传输 保证数据传输的完整性&#xff1a;两方都完成了数据发送和接收并且都同意断开连接 可靠地终止连接以及避免数据混淆和错误等需求:每个方向都需要单独确认导致四次挥手过程 这些…

Opengl光照测试

代码 #include "Model.h" #include "shader_m.h" #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" //以上是放在同目录的头文件#include <glad/glad.h> #include <GLFW/glfw3.…

【MySQL】SQL语言

【MySQL】SQL语言 文章目录 【MySQL】SQL语言前言一、SQL的通用语法二、SQL的分类三、SQLDDLDMLDQLDCL 总结 前言 本篇文章将讲到SQL语言&#xff0c;包括SQL的通用语法,SQL的分类,以及SQL语言的DDL,DML,DQL,DCL。 一、SQL的通用语法 在学习具体的SQL语句之前&#xff0c;先来…

.netcore + postgis 保存地图围栏数据

一、数据库字段 字段类型选择(Type) 设置对象类型为&#xff1a;geometry 二、前端传递的Json格式转换 前端传递围栏的各个坐标点数据如下&#xff1a; {"AreaRange": [{"lat": 30.123456,"lng": 120.123456},{"lat": 30.123456…

T265相机双目鱼眼+imu联合标定(全记录)

最近工作用到t265&#xff0c;记录一遍标定过程 1.安装驱动 首先安装realsense驱动&#xff0c;因为笔者之前使用过d435i&#xff0c;装的librealsense版本为2.55.1&#xff0c;直接使用t265会出现找不到设备的问题&#xff0c;经查阅发现是因为realsense在2.53.1后就不再支持…

【C语言指南】C语言内存管理 深度解析

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C语言指南》 期待您的关注 引言 C语言是一种强大而灵活的编程语言&#xff0c;为程序员提供了对内存的直接控制能力。这种对内存…

Python学习从0到1 day26 第三阶段 Spark ④ 数据输出

半山腰太挤了&#xff0c;你该去山顶看看 —— 24.11.10 一、输出为python对象 1.collect算子 功能: 将RDD各个分区内的数据&#xff0c;统一收集到Driver中&#xff0c;形成一个List对象 语法&#xff1a; rdd.collect() 返回值是一个list列表 示例&#xff1a; from …

【机器学习】机器学习中用到的高等数学知识-1.线性代数 (Linear Algebra)

向量(Vector)和矩阵(Matrix)&#xff1a;用于表示数据集&#xff08;Dataset&#xff09;和特征&#xff08;Feature&#xff09;。矩阵运算&#xff1a;加法、乘法和逆矩阵(Inverse Matrix)等&#xff0c;用于计算模型参数。特征值(Eigenvalues)和特征向量(Eigenvectors)&…

java项目-jenkins任务的创建和执行

参考内容: jenkins的安装部署以及全局配置 1.编译任务的general 2.源码管理 3.构建里编译打包然后copy复制jar包到运行服务器的路径 clean install -DskipTests -Pdev 中的-Pdev这个参数用于激活 Maven 项目中的特定构建配置&#xff08;Profile&#xff09; 在 pom.xml 文件…