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

Java后端开发day46--多线程(二)

请添加图片描述
(以下内容全部来自上述课程)
在这里插入图片描述

多线程

1. Lock锁

虽然我们可以理解同步代码块和同步方法的锁对象问题,
但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

手动上锁、手动释放锁
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作 Lock中提供了获得锁和释放锁的方法
void lock():获得锁
void unlock():释放锁

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化 ReentrantLock的构造方法
ReentrantLock():创建一个ReentrantLock的实例

请添加图片描述

2. 死锁(错误)

锁的嵌套容易导致死锁
请添加图片描述

3. 等待唤醒机制(生产者和消费者)

生产者消费者模式是一个十分经典的多线程协作的模式。
请添加图片描述
请添加图片描述

3.1 消费者:消费数据----消费者等待

请添加图片描述

  1. Desk:
package com.itheima.a13waitandnotify;public class Desk {/**作用:控制生产者和消费者的执行** *///是否有面条0:没有面条1:有面条 public static int foodFlag = 0;//总个数public static int count = 10;//锁对象public static 0bject lock = new 0bject();
}
  1. Foodie:
package com.itheima.a13waitandnotify;
public class Foodie extends Thread{@Overridepublic void run(){/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾(到了末尾)* 4.判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)**/while(true){synchronized (Desk.lock){if(Desk.count ==0){break;}else{//先判断桌子上是否有面条 if(Desk.foodFlag == 0){//如果没有,就等待 try{Desk.lock.wait();//让当前线程跟锁进行绑定} catch (InterruptedException e) {e.printStackTrace();}	I	}else{//把吃的总数-1 Desk.count--;//如果有,就开吃System.out.println("吃货在吃面条,还能再吃”+ Desk.count + "!!!");//吃完之后,唤醒厨师继续做 Desk. Lock.notifyA11();//修改桌子的状态 Desk.foodFLag =0;}}}}}}

3.2 生产者:生产数据----生产者等待

请添加图片描述

  1. Cook
package com.itheima.a13waitandnotify;
public class Cook extends Thread{@Overridepublic void run(){/** 1.循环*2.同步代码块* 3.判断共享数据是否到了末尾(到了末尾)* 4.判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)* */while (true){synchronized (Desk.Lock){if(Desk.count ==0){break;}else{//判断桌子上是否有食物 if(Desk.foodFlag == 1){//如果有,就等待 try {Desk.Lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else{//如果没有,就制作食物System.out.println("厨师做了一碗面条");//修改桌子上的食物状态 Desk.foodFLag = 1;//叫醒等待的消费者开吃 Desk.ymck.notifyA11();}}}}}
}
  1. 测试类
package com.itheima.a13waitandnotify;public class ThreadDemo {public static void main(String[] args) {/***	需求:完成生产者和消费者(等待唤醒机制)的代码	*	实现线程轮流交替执行的效果	** *///创建线程的对象Cook c = new Cook();Foodie f = new Foodie();//给线程设置名字 c.setName("厨师"); f.setName("吃货");//开启线程 c.start(); f.start();}
}

3.3 阻塞队列方式实现

请添加图片描述
请添加图片描述

  1. TreadDemo:
package com.itheima.a14waitandnotify;import java.util.concurrent.ArrayBlockingQueue;
public class ThreadDemo {public static void main(String[] args){/***	需求:利用阻塞队列完成生产者和消费者(等待唤醒机制)的代码	细节:*	生产者和消费者必须使用同一个阻塞队列	** *///1.创建阻塞队列的对象ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(capacity: 1);//2.创建线程的对象,并把阻塞队列传递过去 Cook c = new Cook(queue);Foodie f = new Foodie(queue);//3.开启线程 c.start(); f.start();}
}
  1. Cook:
package com.itheima.a14waitandnotify;
import java.util.concurrent.ArrayBlockingQueue;
public class Cook extends Thread{ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不断的把面条放到阻塞队列当中 try {queue.put( e: "面条");System.out.println("厨师放了一碗面条”)} catch (InterruptedException e) {e.printStackTrace();}}}
}
  1. Foodie:
package com.itheima.a14waitandnotify;
import java.util.concurrent.ArrayBlockingQueue;
public class Foodie extends Thread{ArrayBlockingQueue<String> queue;public Foodie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不断从阻塞队列中获取面条 try {String food = queue.take(); System.out.println(food);} catch (InterruptedException e) {e.printStackTrace();}}}
}

4. 线程的状态

Java中没有定义运行状态。
请添加图片描述
实际上:
请添加图片描述

5. 线程池

一个存放线程的容器。

5.1 主要核心原理

  1. 创建一个池子,池子中是空的

  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可

  3. 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

5.2 方法

请添加图片描述

public class MyThreadPoolDemo {public static void main(String[] args) {/*public static ExecutorService newCachedThreadPool()	创建一个没有上限的线程池	public static ExecutorService newFixedThreadPool (int nThreads)创建有上限的线程池*///1.获取线程池对象ExecutorService pool1= Executors.newCachedThreadPool();//2.提交任务pool1.submit(new MyRunnable()); pool1.submit(new MyRunnable());|//3.销毁线程池//pool1.shutdown();}
}

5.3 自定义线程池

请添加图片描述
队伍满了之后才会启用临时线程,直接执行没在队伍内的任务。
超出核心线程+临时线程+队伍长处加起来的和的任务,通常会触发任务拒绝策略。
请添加图片描述
请添加图片描述

/*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);
参数一:核心线程数量	不能小于0	
参数二:最大线程数	不能小于0,最大数量>=核心线程数量	
参数三:空闲线程最大存活时间	不能小于0	
参数四:时间单位	用TimeUnit指定	
参数五:任务队列	不能为nu11	
参数六:创建线程工厂	不能为nu11	
参数七:任务的拒绝策略	不能为nu11	*/ThreadPoolExecutor pool = new ThreadPoolExecutor(corePoolSize: 3//核心线程数量,能小于0maximumPoolSize: 6//最大线程数,不能小于0,最大数量>=核心线程数量 keepAliveTime: 60,//空闲线程最大存活时间 TimeUnit.SECONDS,//时间单位new ArrayBlockingQueue<>(capacity: 3),//任务队列 Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略
);
  1. 创建一个空的池子
  2. 有任务提交时,线程池会创建线程去执行任务,执行完毕归还线程

不断的提交任务,会有以下三个临界点:

  1. 当核心线程满时,再提交任务就会排队
  2. 当核心线程满,队伍满时,会创建临时线程
  3. 当核心线程满,队伍满,临时线程满时,会触发任务拒绝策略

6.最大并行数

与CPU有关
4核8线程:

  1. 4核:4个大脑,可以同时干4件事 -->超线程技术 --> 8线程
  2. 8线程:最大并行数为8

7. 线程池多大合适

  • CPU密集型运算:计算比较多,读取本地文件或数据库较少 --> 最大并行数+1
  • I/O密集型运算:读取本地文件或数据库比较多(大多数都是此类)
    请添加图片描述
    公式举例:
    请添加图片描述

相关文章:

  • 互联网大厂Java求职面试实战:Spring Boot微服务与数据库优化详解
  • rust-candle学习笔记12-实现因果注意力
  • 数据结构精解:优先队列、哈希表与树结构
  • 【Redis】string
  • Exploring Temporal Event Cues for Dense Video Captioning in Cyclic Co-Learning
  • 【C++指南】STL容器的安全革命:如何封装Vector杜绝越界访问与迭代器失效?
  • [论文阅读]BadPrompt: Backdoor Attacks on Continuous Prompts
  • 提高工作效率的新选择[特殊字符]——Element Plus UI库
  • HNUST湖南科技大学-软件测试期中复习考点(保命版)
  • window环境下,如何通过USB接口控制打印机
  • Spring MVC 视图解析器 (ViewResolver) 如何配置? Spring Boot 是如何自动配置常见视图解析器的?
  • idea如何快速生成测试类
  • 【DLF】基于语言的多模态情感分析
  • 如何阅读、学习 Linux 2 内核源代码 ?
  • 《AI大模型应知应会100篇》第54篇:国产大模型API对比与使用指南
  • 2025数维杯数学建模A题完整参考论文(共36页)(含模型、可运行代码、数据)
  • 内存安全暗战:从 CVE-2025-21298 看 C 语言防御体系的范式革命
  • mmcv低版本报错大全
  • Innovus 25.1 版本更新:助力数字后端物理设计新飞跃
  • 通俗易懂版知识点:Keepalived + LVS + Web + NFS 高可用集群到底是干什么的?
  • 傅利叶提出下个十年战略,CEO顾捷:机器人要有温度,要用实际价值来定义形态
  • 竞彩湃|德甲欧冠资格竞争白热化,伯恩茅斯主场迎恶战
  • 西安机场回应航站楼“水帘洞”事件:屋面排水系统被冰雹堵塞
  • 洲际酒店:今年第一季度全球酒店平均客房收入同比增长3.3%
  • 苹果Safari浏览器上的搜索量首次下降
  • 技术派|伊朗展示新型弹道导弹,美“萨德”系统真的拦不住?