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

Java Day13 多线程

多线程

  • 1、 方式一 Thread
  • 2、实现Runnable接口
  • 3、实现 Callable接口
  • 4、与线程有关的操作方法
  • 5、线程安全问题
    • 5.1 取钱案例
    • 5.2 线程同步
      • 5.2.1 同步代码块
      • 5.2.2 同步方法
      • 5.2.3 Lock锁
  • 6、线程池
    • 6.2 创建线程池
      • 6.2.1 使用ExecutorService创建
      • 新任务策略
      • 6.2.2 使用Executors工具类创建
      • 核心线程数量问题
  • 7、并发、并行,线程生命周期
  • 7、乐观锁、悲观锁

1、 方式一 Thread

继承 Thread类
优点:编码简单
缺点:java是单继承,继承了一个类,就不能继承其他,可拓展性不强。

注意:
①子线程一定要调用start方法,而不是run方法,调用run方法,还是相当于在main线程中创建了一个实例对象,在运行她的方法, 而已,是单线程的。调用strat方法,虽然底层还是调用run方法,但是他会告诉cpu说我们另外启动了一个线程。
②子线程启动一定要在主线程任务之前。
③每次执行的结果会不同。

package com.cky.file;public class MyThread extends  Thread{@Overridepublic void run() {for (int i = 0; i <5 ; i++) {System.out.println("子线程"+i);}}
}
package com.cky.file;public class Endecode {public static void main(String[] args) throws Exception {Thread thread=new MyThread();thread.start();for (int i = 0; i <5 ; i++) {System.out.println("主线程"+i);}}}

2、实现Runnable接口

在这里插入图片描述

package com.cky.file;public class MyRunnable implements  Runnable{@Overridepublic void run() {for (int i = 0; i <5 ; i++) {System.out.println("子线程"+i);}}
}
package com.cky.file;public class Endecode {public static void main(String[] args) throws Exception {//创建一个任务对象MyRunnable myRunnable=new MyRunnable();//调用线程类的start方法new Thread(myRunnable).start();//匿名内部类Runnable runnable = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程" + i);}}};new Thread(runnable).start();//简化形式1new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程" + i);}}}).start();//形式2new Thread(()-> {for (int i = 0; i < 5; i++) {System.out.println("子线程" + i);}}).start();for (int i = 0; i <5 ; i++) {System.out.println("主线程"+i);}}}

由于Runnable是一个函数式接口,匿名内部类可以使用lambda形式
在这里插入图片描述

3、实现 Callable接口

上边两种实现方法,都不能获得线程执行的结果并返回,方法3可以。
实现Callable接口 将该接口 封装为一个FutureTask 任务对象,最后在交给线程。
是一个泛型接口 这里String 是要返回的类型 可以定义为其他类型

package com.cky.file;import java.util.concurrent.Callable;public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum=0;for (int i = 1; i <= n; i++) {sum+=i;}return "1-"+n+"的和为:"+sum;}
}
package com.cky.file;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class Endecode {public static void main(String[] args) throws Exception {//创建一个Callable对象Callable<String> callable=new MyCallable(100);//封装为一个FutureTask对象//FutureTask 是一个任务对象 实现了Runnable接口// 在执行完毕后 可以通过get方法获得执行结果FutureTask<String> f1 = new FutureTask<>(callable);//交给一个Thread对象new Thread(f1).start();//获得执行结果 注意:执行未结束 是不会取得结果的String s = f1.get();System.out.println(s);//1-100的和为:5050}}

在这里插入图片描述

4、与线程有关的操作方法

在这里插入图片描述

package com.cky.file;public class MyThread extends  Thread{public MyThread( String name){super(name);}@Overridepublic void run() {Thread t=Thread.currentThread();for (int i = 0; i <3 ; i++) {System.out.println(t.getName()+i);}}
}
package com.cky.file;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class Endecode {public static void main(String[] args) throws Exception {MyThread myThread1=new MyThread("子线程1");//修改名字
//        myThread1.setName("子线程1");myThread1.start();MyThread myThread2=new MyThread("子线程2");
//        myThread2.setName("子线程2");myThread2.start();//哪个线程在执行 就是哪个线程Thread m = Thread.currentThread();String name = m.getName();System.out.println(name);for (int i = 0; i < 3; i++) {System.out.println(name+"线程"+i);}}}
package com.cky.file;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class Endecode {public static void main(String[] args) throws Exception {
//当输出为3时 ,延缓5秒在运行for (int i = 0; i < 5; i++) {System.out.println(i);if(i==3)Thread.sleep(5000);}}}
package com.cky.file;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class Endecode {public static void main(String[] args) throws Exception {MyThread myThread1=new MyThread("子线程1");myThread1.start();myThread1.join();//当前线程执行完毕 再往下进行MyThread myThread2=new MyThread("子线程2");myThread2.start();myThread2.join();Thread m = Thread.currentThread();String name = m.getName();System.out.println(name);for (int i = 0; i < 3; i++) {System.out.println(name+"线程"+i);}}}

子线程10
子线程11
子线程12
子线程20
子线程21
子线程22
main
main线程0
main线程1
main线程2

5、线程安全问题

5.1 取钱案例

造成线程安全问题原因:
同时存在多个线程,访问同一个共享资源,且都要修改该共享资源。
同时进入钱够的判断,造成线程 不安全

package com.cky.file;public class Account {private double money;public Account(double money) {this.money = money;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}public void drawmoney(double money){String name=Thread.currentThread().getName();if (this.money>=money){System.out.println(name+"来取钱成功");this.money-=money;System.out.println(name+"取后,剩余:"+this.money);}else{System.out.println("钱不够");}}
}
package com.cky.file;public class MyThread extends  Thread{private Account account;public MyThread( Account account,String name){super(name);this.account=account;}@Overridepublic void run() {
//取钱account.drawmoney(10000);}}
package com.cky.file;import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;public class Endecode {public static void main(String[] args) {//创建一个共享账户Account account=new Account(10000);//两个线程MyThread myThread1=new MyThread(account,"小红");MyThread myThread2=new MyThread(account,"小明");myThread1.start();myThread2.start();}}

小红来取钱成功
小明来取钱成功
小红取后,剩余:0.0
小明取后,剩余:-10000.0

5.2 线程同步

解决线程安全问题的办法
在这里插入图片描述
在这里插入图片描述

5.2.1 同步代码块

  public void drawmoney(double money){String name=Thread.currentThread().getName();synchronized (this) {if (this.money>=money){System.out.println(name+"来取钱成功");this.money-=money;System.out.println(name+"取后,剩余:"+this.money);}else{System.out.println("钱不够");}}

实例方法 同步代码块 通常加this 代表当前资源 比如小红和小黑共享一个账户 小白和小亮共享一个账户,使用this 保证了 只锁住同一个账户 不被多个访问 但不会去锁住别人的账户。
如果是静态方法 每个类只有一份 只允许一个访问 通常用 类.class 来锁住所有,只允许一个人访问。

   public static void text(){synchronized (Account.class){}}

在这里插入图片描述

5.2.2 同步方法

 public synchronized void drawmoney(double money){String name=Thread.currentThread().getName();if (this.money>=money) {System.out.println(name + "来取钱成功");this.money -= money;System.out.println(name + "取后,剩余:" + this.money);}else{System.out.println("钱不够");}}

在这里插入图片描述

5.2.3 Lock锁

在这里插入图片描述

package com.cky.file;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Account {private double money;//为每个账户创建一个锁对象private final Lock lock=new ReentrantLock();public Account(double money) {this.money = money;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}public void drawmoney(double money){String name=Thread.currentThread().getName();//加锁lock.lock();try {if (this.money>=money) {System.out.println(name + "来取钱成功");this.money -= money;System.out.println(name + "取后,剩余:" + this.money);}else{System.out.println("钱不够");}} catch (Exception e) {e.printStackTrace();}finally {//写在finally里,为了防止上边代码出错,导致没有解锁lock.unlock();}}
}

6、线程池

如果每一个线程都需要我们去新创建一个线程的话,就会耗资源并且耗时(创建线程是一件耗时的事)
此时就需要线程池,线程池可以复用线程,不用经常去创建线程。
并且线程池也可以确定任务队列中任务的个数。防止任务过多,导致内存溢出。
在这里插入图片描述

6.2 创建线程池

在这里插入图片描述

6.2.1 使用ExecutorService创建

在这里插入图片描述
在这里插入图片描述

package com.cky.file;public class MyRunnable implements  Runnable{private int n;public MyRunnable(int n) {this.n = n;}@Overridepublic void run()  {int sum=0;for (int i = 1; i <= n; i++) {sum+=i;}System.out.println(Thread.currentThread().getName()+"-1-"+n+"的和为:"+sum);try {Thread.sleep(100000);} catch (InterruptedException e) {e.printStackTrace();}}
}
package com.cky.file;import java.util.concurrent.*;public class Endecode {public static void main(String[] args) {//创建一个线程池对象/* 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());MyRunnable myRunnable=new MyRunnable(100);pool.execute(myRunnable);pool.execute(myRunnable);pool.execute(myRunnable);//开始往任务队列加pool.execute(myRunnable);pool.execute(myRunnable);pool.execute(myRunnable);pool.execute(myRunnable);//开始使用临时线程pool.execute(myRunnable);pool.execute(myRunnable);
//        开始使用任务队列满的措施pool.execute(myRunnable);}}
D:\JAVA\jdk-17.0.8\bin\java.exe "-javaagent:D:\SOftware\idea\IntelliJ IDEA 2021.3.2\lib\idea_rt.jar=49289:D:\SOftware\idea\IntelliJ IDEA 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath E:\java_code\project\out\production\hello-app;E:\java_code\project\hello-app\lib\dom4j-2.1.4.jar;E:\java_code\project\hello-app\lib\commons-io-2.15.1.jar com.cky.file.Endecode
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@5b480cf9[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@5f184fc6[Wrapped task = com.cky.file.MyRunnable@3feba861]] rejected from java.util.concurrent.ThreadPoolExecutor@6f496d9f[Running, pool size = 5, active threads = 5, queued tasks = 4, completed tasks = 0]at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2065)at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:833)at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123)at com.cky.file.Endecode.main(Endecode.java:31)
pool-1-thread-1-1-100的和为:5050
pool-1-thread-2-1-100的和为:5050
pool-1-thread-5-1-100的和为:5050
pool-1-thread-3-1-100的和为:5050
pool-1-thread-4-1-100的和为:5050

//我们可以看到 使用了临时线程 并且使用了任务满时的策略。

新任务策略

在这里插入图片描述

package com.cky.file;import java.util.concurrent.Callable;public class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum=0;for (int i = 1; i <= n; i++) {sum+=i;}return Thread.currentThread().getName()+"-1-"+n+"的和为:"+sum;}
}
package com.cky.file;import java.util.concurrent.*;public class Endecode {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建一个线程池对象/* 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());Future<String> f1 = pool.submit(new MyCallable(100));Future<String> f2 = pool.submit(new MyCallable(200));Future<String> f3 =pool.submit(new MyCallable(300));Future<String> f4 =pool.submit(new MyCallable(400));System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());}}

pool-1-thread-1-1-100的和为:5050
pool-1-thread-2-1-200的和为:20100
pool-1-thread-3-1-300的和为:45150
pool-1-thread-3-1-400的和为:80200

6.2.2 使用Executors工具类创建

在这里插入图片描述
在这里插入图片描述
创建单个线程池

   ExecutorService pool = Executors.newSingleThreadExecutor();pool.execute(new MyRunnable(100));

使用该种方式的风险
在这里插入图片描述

核心线程数量问题

如果时IO密集型 则一般配置 cpu数量*2
如果是计算密集型 则一般是 cpu数量+1

7、并发、并行,线程生命周期

在这里插入图片描述

并发
在这里插入图片描述
并行
在这里插入图片描述
在这里插入图片描述
生命周期
在这里插入图片描述
在这里插入图片描述

7、乐观锁、悲观锁

悲观锁:一上来就加锁,线程安全,性能较差。
乐观锁:不加锁,等到要开始出现线程安全问题时,才开始控制。

package com.cky.file;import java.util.concurrent.atomic.AtomicInteger;public class MyRunnable implements  Runnable{private AtomicInteger count=new AtomicInteger();@Overridepublic void run()  {for (int i = 0; i <100 ; i++) {System.out.println(Thread.currentThread().getName()+"count===>"+count.incrementAndGet());}}
}
package com.cky.file;import java.util.concurrent.*;public class Endecode {public static void main(String[] args) throws ExecutionException, InterruptedException {//乐观锁//100个线程 对一个变量 各加100次MyRunnable myRunnable=new MyRunnable();for (int i = 0; i <100 ; i++) {new Thread(myRunnable).start();}}}

相关文章:

Java Day13 多线程

多线程 1、 方式一 Thread2、实现Runnable接口3、实现 Callable接口4、与线程有关的操作方法5、线程安全问题5.1 取钱案例5.2 线程同步5.2.1 同步代码块5.2.2 同步方法5.2.3 Lock锁 6、线程池6.2 创建线程池6.2.1 使用ExecutorService创建新任务策略6.2.2 使用Executors工具类创…...

以太坊的演变:EIP、ERC 概念以及革命性的 ERC20、ERC721 和 ERC115 标准

文章目录 一、EIP——以太坊发展的基石1.1 什么是EIP&#xff1f;1.2 历史背景&#xff1a;前身的 BIP1.3 EIP的重要性1.4 流程&#xff1a;从提案到实施 二、进入 ERC——以太坊内的标准化协议2.1 解读 ERC&#xff1a;以太坊征求意见2.2 ERC 标准的诞生和意义 三、聚焦 ERC20…...

B003-springcloud alibaba 服务治理 nacos discovery ribbon feign

目录 服务治理服务治理介绍什么是服务治理相关方案 nacos实战入门搭建nacos环境安装nacos启动nacos访问nacos 将商品微服务注册进nacos将订单微服务注册进nacos订单服务通过nacos调用商品服务 实现服务调用的负载均衡什么是负载均衡代码实现负载均衡增加一个服务提供者自定义实…...

mac笔记本执行定时任务

1.mac本地设置一个定时任务每小时执行一次&#xff0c;在/Users/xxx/go/src/runing目录下执行命令&#xff1a;./git_push.sh 在macOS中&#xff0c;你可以使用crontab来设置定时任务。打开终端并执行以下步骤&#xff1a; 1.打开当前用户的crontab编辑器&#xff1a; crontab …...

解决linux系统网卡加载慢的问题

手上有块开发板&#xff0c;启动系统后&#xff0c;需要五六分钟后无线wifi网卡才能加载起来&#xff0c;网卡型号是qca9377。 第一步先确认是不是第一时间挂载到PCI总线上了&#xff0c;在ath10k_pci_probe函数中添加调试信息&#xff0c;另外查看/sys/bus/pci/drivers/ath10…...

Linux 命令或者一些工具

locale – 设置和显示程序运行的语言环境 locale -a | grep en_US.UTF-8.sudo locale-gen en_US.UTF-8sudo dpkg-reconfigure localesexpect 常用命令总结 expect命令spawnexpectsendexp_continuesend_userexit chrpath工具 chrpath 是一个用于修改可执行文件或共享库的运行…...

基于python的4s店客户管理系统

技术&#xff1a;pythonmysqlvue 一、背景 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使管理系统的发展。网上办公可以实现远程处理事务…...

解决谷歌浏览器最新chrome94版本CORS跨域问题

项目场景&#xff1a; 谷歌浏览器升级到chrome94版本出现CORS跨域问题 问题描述 解决谷歌浏览器最新chrome94版本CORS跨域问题。 CORS跨域问题&#xff1a; 升级谷歌浏览器最新chrome94版本后&#xff0c;提示Access to XMLHttpRequest at ‘http://localhost:xxxx/api’ fro…...

JAVA 线程

目录 一、线程的定义 二、线程的实现 三、线程状态 程序并发执行多个任务 二、线程的实现 1、继承Thread类创建线程&#xff1a;通过继承Java的Thread类并重写其run()方法&#xff0c;可以创建一个新的线程。然后&#xff0c;通过调用线程的start()方法来启动线程&#xf…...

Rust 基于 await、async 的异步编程和纤程、协程的实现

一、Rust 的异步编程 Rust 通过 await、async 实现了其他语言中纤程、协程的机制。下面是一个使用async和await的Rust示例代码。这个示例展示了如何异步地读取文件内容。 首先&#xff0c;确保你的Cargo.toml文件包含了tokio库的依赖&#xff0c;如下&#xff1a; [dependen…...

【进阶五】Python实现SDVRP(需求拆分)常见求解算法——差分进化算法(DE)

基于python语言&#xff0c;采用经典差分进化算法&#xff08;DE&#xff09;对 需求拆分车辆路径规划问题&#xff08;SDVRP&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整3. 求解结果4. 代码片段参考 往期优质资源 经过一年多的创作&#xff0c;目前已经成…...

什么是神经网络?

一、什么是神经网络&#xff1f; 神经网络又称人工神经网络&#xff0c;是一种基于人脑功能模型的计算架构&#xff0c;因此称之为“神经”。神经网络由一组称为“节点”的处理单元组成。这些节点相互传递数据&#xff0c;就像大脑中的神经元相互传递电脉冲一样。 神经网络在…...

基于Python的图形用户界面设计及应用

基于Python的图形用户界面设计及应用 摘要&#xff1a;随着信息技术的飞速发展&#xff0c;图形用户界面&#xff08;GUI&#xff09;已成为现代软件不可或缺的一部分。Python作为一种简洁、易读且功能强大的编程语言&#xff0c;提供了多种GUI开发工具包&#xff0c;如Tkinte…...

python网络爬虫实战教学——urllib的使用(1)

文章目录 专栏导读1、前言2、urllib的使用3、发送请求3.1 urlopen3.2 request 专栏导读 ✍ 作者简介&#xff1a;i阿极&#xff0c;CSDN 数据分析领域优质创作者&#xff0c;专注于分享python数据分析领域知识。 ✍ 本文录入于《python网络爬虫实战教学》&#xff0c;本专栏针对…...

简述归并排序

归并排序 特点&#xff1a; 高效稳定时间复杂度最佳/平均/最差&#xff1a; O(N log N) 递归算法有专门的公式来计算时间复杂度 空间复杂度 O(N) 因为开辟了临时的tem_arr数组 一个静态的演示图(from leetcode) 一个动态的演示图 合并实现使用merge函数 inline void merge(v…...

HTML实现卷轴动画完整源码附注释

动画效果截图 页面的html结构代码 <!DOCTYPE html> <html> <head lang=...

sh: 1: dtc: not found

报错&#xff1a; bl31.bin size: 41632 u-boot-nodtb.bin size: 815816 ai_robot.dtb size: 30552 ./mkimage_uboot -E -p 0x3000 -f u-boot-ai-robot.its u-boot-ai-robot.itb sh: 1: dtc: not found ./mkimage_uboot: Cant open u-boot-ai-robot.itb.tmp: No such file …...

laravel 表单验证的 exists、unique 去除软删除字段的校验

use Illuminate\Validation\Rule; exists 去除软删除字段的校验 $validator \Validator::make($data, [phone_new > [Rule::exists(users, phone)->whereNull(deleted_at),]], [phone_new.exists > 手机号不存在,]);unique 去除软删除字段的校验 // 新增 email>r…...

【PHP + 代码审计】函数详解2.0

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…...

宠物智能喂食机方案设计

我们都知道&#xff0c;现如今养宠物的人群已经很多了&#xff0c;主要是青年人居多&#xff0c;他们在独自漂泊的在外的工作&#xff0c;免不了情感泛滥&#xff0c;养一些小动物也是在预料之中。但由于工作或者其他各种因数&#xff0c;养宠人不可时时刻刻在家&#xff0c;对…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...