制作网站建设的/湖南seo优化排名

制作网站建设的,湖南seo优化排名,滕州网站建设培训,设计一个营销方案【JavaEE】多线程进阶(2) 一、JUC(java.util.concurrent) 的常⻅类1.1 Callable 接⼝1.2 ReentrantLock1.3 原子类原子类的特性:常见原子类:原子类的实例: 1.4 线程池1.5 信号量 Semaphore代码实例 1.6 CountDownLatch…

【JavaEE】多线程进阶(2)

  • 一、JUC(java.util.concurrent) 的常⻅类
      • 1.1 Callable 接⼝
      • 1.2 ReentrantLock
      • 1.3 原子类
        • 原子类的特性:
        • 常见原子类:
        • 原子类的实例:
      • 1.4 线程池
      • 1.5 信号量 Semaphore
        • 代码实例
      • 1.6 CountDownLatch
        • 代码实例
      • 1.7 线程安全的集合类
        • 多线程环境使⽤ ArrayList
        • 多线程环境使⽤哈希表
        • Hashtable
        • ConcurrentHashMap
      • 1.8 死锁

一、JUC(java.util.concurrent) 的常⻅类

博客结尾附有此篇博客的全部代码!!!

1.1 Callable 接⼝

Callable 接口是 Java 中用于定义可以返回结果的任务的接口,它位于 java.util.concurrent 包中。

public interface Callable<V> {V call() throws Exception;
}

实例应用:计算1+2+…+100的值,使用Callable接口

   public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable = new Callable<Integer>() {public Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 100; i++) {sum += i;}return sum;}};Thread thread = new Thread(callable);thread.start();}

在这里插入图片描述
原因:Thread本身不提供接受结果的方法,需要FutureTask对象来拿到结果(Thread不提供接受结果是为了更好的解耦合,将任务和线程分离开)

  • FutureTask:FutureTask 实现了 Runnable 接口,因此可以被 Thread 接受。
  • Thread类的构造函数可以接受一个 Runnable 对象,但不能接受其他类型的对象,因为 Thread 的内部逻辑是基于 Runnable 的 run() 方法实现的。

修改:

public class CallableDemo {public static void main(String[] args) throws InterruptedException, ExecutionException {Callable<Integer> callable=new Callable<Integer>() {public Integer call() throws Exception {int sum=0;for (int i = 0; i <= 100; i++) {sum+=i;}return sum;}};FutureTask<Integer> futureTask=new FutureTask<>(callable);Thread thread=new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}

通过Runnable接口计算1+2+…+100的值:

public class RunnableDemo {private static int total=0;public static void main(String[] args) throws InterruptedException {Runnable r = new Runnable(){int sum=0;public void run() {for (int i = 0; i <=100 ; i++) {sum+=i;}total=sum;}};Thread t1 = new Thread(r);t1.start();t1.join();System.out.println(total);}
}

1.2 ReentrantLock

可重⼊互斥锁. 和 synchronized 定位类似, 都是⽤来实现互斥效果, 保证线程安全

ReentrantLock 的核心功能是通过 Lock 接口实现的,它提供了以下方法:

  • lock():获取锁,如果锁已经被其他线程占用,则当前线程会阻塞,直到获取锁。
  • unlock():释放锁。
  • tryLock():尝试获取锁,如果锁可用则立即获取,否则返回 false,不会阻塞。
  • tryLock(long timeout, TimeUnit unit):尝试获取锁,如果在指定时间内无法获取锁,则返回 false。
  • isHeldByCurrentThread():判断当前线程是否持有该锁。
  • isLocked():判断锁是否被任何线程持有。
public class ReentrantLockDemo1 {private static int total = 0;public static void main(String[] args) throws InterruptedException {ReentrantLock locker = new ReentrantLock();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {locker.lock();total++;locker.unlock();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {locker.lock();total++;locker.unlock();}});t1.start();t2.start();t1.join();t2.join();System.out.println(total);}
}

运行结果:total=100000
这里需要注意的:
因为这里解锁需要自己手动解锁,但是不可避免的抛出异常而导致代码运行终止,有可能就执行不到 locker.lock();
改进:将unlocker.lock();放入finally代码块中
在这里插入图片描述
ReentrantLock和synchronized对比:

  1. synchronized是关键字,ReentrantLock是Java的标准库中的类
  2. synchronized是通过代码块执行加锁解锁,而ReentrantLock是通过lock()和unlock()加锁解锁,需要注意的是unlock()不调用问题
  3. ReentrantLock提供的tryLock(),如果成功加锁,返回true;反之,加锁失败,返回false,不会出现阻塞;而且还可以设置等待时长,在这段时间后再尝试加锁,返回true/false。
  4. synchronized是非公平锁,ReentrantLock默认是非公平锁,但是可以设置为公平锁
ReentrantLock lock = new ReentrantLock(true);
  1. 更强⼤的唤醒机制. synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是⼀个随机等待的线程. ReentrantLock 搭配Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定线程。

1.3 原子类

原子类通过提供一系列线程安全的变量操作方法,确保在多线程环境下对变量的读写操作是不可分割的(即原子的)。它们利用了底层硬件的原子操作指令(如 CAS),从而避免了锁的开销,提高了性能。

原子类的特性:
  • 无锁并发:原子类通过 CAS 机制实现线程安全,无需使用重量级的锁(如 synchronized 或 ReentrantLock)。
  • 高性能:由于避免了锁的开销,原子类在高并发场景下通常比传统同步机制性能更高。
  • 线程安全:原子类保证了对变量的操作是原子的,即使在多线程环境下也不会出现竞态条件。
常见原子类:

(1)基本类型原子类:
AtomicInteger:用于原子操作的整数。
AtomicLong:用于原子操作的长整型。
AtomicBoolean:用于原子操作的布尔值。
(2)引用类型原子类:
AtomicReference:用于原子操作的对象引用。
AtomicStampedReference:用于原子操作的对象引用,同时带有版本号(用于解决 ABA 问题)。
AtomicMarkableReference:用于原子操作的对象引用,同时带有布尔标记。
(3)数组类型原子类:
AtomicIntegerArray:用于原子操作整型数组。
AtomicLongArray:用于原子操作长整型数组。
AtomicReferenceArray:用于原子操作对象引用数组。

原子类的实例:

基本类型原子类:AtomicInteger:用于原子操作的整数

public class AtomicIntegerArrayDemo1 {public static void main(String[] args) {AtomicInteger atomicInt = new AtomicInteger(2);atomicInt.incrementAndGet(); // 增加 1atomicInt.addAndGet(2);      // 增加 5atomicInt.compareAndSet(5, 10); // 如果当前值为 5,则设置为 10System.out.println(atomicInt.get());//这里获取的是10}
}
public class AtomicIntegerArrayDemo {public static void main(String[] args) throws InterruptedException {AtomicInteger atomicInt = new AtomicInteger(0);Thread t1 = new Thread(() -> {for(int i = 0; i < 5000;i++ ){atomicInt.incrementAndGet();}});Thread t2 = new Thread(() -> {for(int i = 0; i < 5000;i++ ){atomicInt.incrementAndGet();}});t1.start();t2.start();t1.join();t2.join();System.out.println(atomicInt.get());//获取的是10000}
}

引用类型原子类:AtomicStampedReference:用于原子操作的对象引用,同时带有版本号。

public class AtomicStampedReferenceDemo1 {public static void main(String[] args) {AtomicStampedReference<String> ref = new AtomicStampedReference<>("Hello", 0);ref.compareAndSet("Hello", "World",0, 1); // 更新引用和版本号System.out.println(ref.getReference());//expectedStamp和initialStamp相等,// 则更新initialRef引用值为newReference,并且更新版本号}
}

compareAndSet 方法的作用:

  • 检查当前引用值是否为 “Hello”。
  • 检查当前版本号是否为 0。
  • 如果两个条件都满足,则将引用值更新为 “World”,版本号更新为 1
    在这里插入图片描述
    数组类型原子类:AtomicReferenceArray:用于原子操作对象引用数组。
public class AtomicReferenceArrayDemo {public static void main(String[] args) {AtomicReferenceArray<String> array = new AtomicReferenceArray<>(new String[]{"Hello", "World"});array.set(1, "Java");//将索引为1的引用改为JavaSystem.out.println(array.get(1));}
}

1.4 线程池

线程池

1.5 信号量 Semaphore

Semaphore 的核心思想是通过一组许可证(permits)来控制对资源的访问。每个线程在访问资源之前,必须先获取一个许可证;访问完成后,释放许可证。许可证的数量是有限的,当许可证用完时,后续的线程将被阻塞,直到有许可证被释放。

代码实例
public class SemaphoreDemo {public static void main(String[] args) throws InterruptedException {Semaphore semaphore = new Semaphore(5);System.out.println("使用第一个许可证");semaphore.acquire();System.out.println("使用第二个许可证");semaphore.acquire();System.out.println("使用第三个许可证");semaphore.acquire();System.out.println("使用第四个许可证");semaphore.acquire();
//        semaphore.release();semaphore.acquire();System.out.println("使用第五个许可证");}
}

在这里插入图片描述
将许可证改为4张,任务还是5个:
在这里插入图片描述
这里可以通过jconsole.exe来调试看下运行结果:
在这里插入图片描述

还是四张许可证,但是这里释放了一张许可证:
在这里插入图片描述

1.6 CountDownLatch

使用多线程,经常将一个大的任务分成多个子任务,使用多线程执行子任务,提高执行效率。

怎么判断子任务全部执行完毕呢?
这里就可以用CountDownLatch来记录各个任务完成。

  1. 构造 CountDownLatch 实例, 初始化 10 表⽰有 10 个任务需要完成.
  2. 每个任务执⾏完毕, 都调⽤ latch.countDown() . 在 CountDownLatch 内部的计数器同时⾃减.
  3. 主线程中使⽤ latch.await(); 阻塞等待所有任务执⾏完毕. 相当于计数器为 0 了
代码实例
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(3);Thread t1 = new Thread(()->{for(int i=0;i<3;i++){try {Thread.sleep((long) (Math.random() * 2000));latch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();latch.await(); // 阻塞主线程,直到计数器为 0System.out.println("所有任务执行完毕");}
}

1.7 线程安全的集合类

Vector, Stack, HashTable, 是线程安全的(不建议⽤), 其他的集合类不是线程安全的

多线程环境使⽤ ArrayList

让ArrayList变成线程安全:

  1. ⾃⼰使⽤同步机制 (synchronized 或者 ReentrantLock)
  2. Collections.synchronizedList(new ArrayList);
    返回List的各种关键方法都带synchronized,这种做法类似于Vector, Stack
  3. 使⽤ CopyOnWriteArrayList
    读操作:读操作直接访问底层数组,不需要加锁,因此性能很高。
    写操作:
  • 创建底层数组的完整副本。
  • 在副本上进行修改操作。
  • 将副本替换为原始数组。
    这种操作的效率相对低效,因为每次都需要复制整个数组。
多线程环境使⽤哈希表

HashMap 本⾝不是线程安全的.
在多线程环境下使⽤哈希表可以使⽤:
• Hashtable
• ConcurrentHashMap

Hashtable
  • 使用全局锁(synchronized)保护整个哈希表(这意味着在任何时刻,只有一个线程可以修改哈希表,其他线程必须等待),所有操作(包括读写)都会锁住整个表。
  • 这种机制简单但效率低下,尤其是在高并发场景下,容易导致线程阻塞。

存在缺点:

  1. 如果多线程访问同⼀个 Hashtable 就会直接造成锁冲突.
  2. size 属性也是通过 synchronized 来控制同步, 也是⽐较慢的.
  3. ⼀旦触发扩容, 就由该线程完成整个扩容过程. 这个过程会涉及到⼤量的元素拷⻉, 效率会⾮常低.
ConcurrentHashMap
  • 使用分段锁(Segment)机制,将哈希表分为多个段,每个段有自己的锁。
  • JDK 1.8 以后,进一步优化为基于 CAS 和 synchronized 的锁机制,结合数组 + 链表 + 红黑树的数据结构。
  • 读操作通常不需要加锁,写操作的锁粒度更细,大大减少了锁竞争。

优化扩容:

  1. 发现需要扩容的线程, 只需要创建⼀个新的数组, 同时只搬⼏个元素过去.
  2. 扩容期间, 新⽼数组同时存在.
  3. 后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运⼀⼩部分元素.
  4. 搬完最后⼀个元素再把⽼数组删掉.
  5. 这个期间, 插⼊只往新数组加.
  6. 这个期间, 查找需要同时查新数组和⽼数组

1.8 死锁

线程安全

此篇博客的全部代码!!!

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

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

相关文章

[漏洞篇]XSS漏洞详解

[漏洞篇]XSS漏洞 一、 介绍 概念 XSS&#xff1a;通过JS达到攻击效果 XSS全称跨站脚本(Cross Site Scripting)&#xff0c;为避免与层叠样式表(Cascading Style Sheets, CSS)的缩写混淆&#xff0c;故缩写为XSS。这是一种将任意 Javascript 代码插入到其他Web用户页面里执行以…

越早越好!8 个反直觉的金钱真相|金钱心理学

很多人都追求财富自由&#xff0c;但成功的人少之又少。 这可能是因为&#xff0c;人们往往忽略了一些金钱的真相和常识。 01 金钱常识 & 真相 为了构建健康的金钱观&#xff0c;我读了一本有点反直觉&#xff0c;有点像鸡汤&#xff0c;但都是财富真相的书。 来自 Morg…

Spring Boot/Spring Cloud 整合 ELK(Elasticsearch、Logstash、Kibana)详细避坑指南

我们在开发中经常会写日志&#xff0c;所以需要有个日志可视化界面管理&#xff0c;使用ELK可以实现高效集中化的日志管理与分析&#xff0c;提升性能稳定性&#xff0c;满足安全合规要求&#xff0c;支持开发运维工作。 下述是我在搭建ELK时遇到的许许多多的坑&#xff0c;希望…

AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异

背景 字节跳动正式发布中国首个AI原生集成开发环境工具&#xff08;AI IDE&#xff09;——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro&#xff0c;支持切换满血版DeepSeek R1&V3&#xff0c; 可以帮助各阶段开发者与AI流畅协作&#xff0c;更快、更高质量地完…

手机屏幕摔不显示了,如何用其他屏幕临时显示,用来导出资料或者清理手机

首先准备一个拓展坞 然后 插入一个外接的U盘 插入鼠标 插入有数字小键盘区的键盘 然后准备一根高清线&#xff0c;一端链接电脑显示器,一端插入拓展坞 把拓展坞的连接线&#xff0c;插入手机充电口&#xff08;可能会需要转接头&#xff09; 然后确保手机开机 按下键盘…

第八届蓝桥杯单片机省赛

什么&#xff1f;你把最近几届省赛真题做完已经无题可做了&#xff0c;那不妨来看看老古董第八届省赛的题目吧&#xff01; 附件&#xff1a;第八届蓝桥杯单片机省赛 一、数码管 1.页面流转 以上的页面流转功能可以用下图总结&#xff1a; #mermaid-svg-38fdQpdydbMy5CyP {fo…

win10电脑鼠标速度突然变的很慢?

电脑鼠标突然变很慢&#xff0c;杀毒检测后没问题&#xff0c;鼠标设置也没变&#xff0c;最后发现可能是误触鼠标的“DPI”调节键。 DPI调节键在鼠标滚轮下方&#xff0c;再次点击即可恢复正常鼠标速度。 如果有和-的按键&#xff0c;速度变快&#xff0c;-速度变慢。 图源&…

【解决哈希冲突】

哈希冲突 如果两个不同的 key 通过哈希函数得到了相同的索引&#xff0c;这种情况就叫做「哈希冲突」。 哈希冲突不可能避免&#xff0c;只能在算法层面妥善处理出现哈希冲突的情况。 哈希冲突是一定会出现的&#xff0c;因为这个 hash 函数相当于是把一个无穷大的空间映射到…

文件操作详解(万字长文)

C语言文件操作 一、为什么使用文件&#xff1f;二、文件分类三、文件的打开和关闭四、文件的顺序读写4.1fputc4.2fgetc4.3fputs4.4fgets4.5 fprintf4.6 fscanf4.7 fwrite4.8 fread 五、文件的随机读写5.1 fseek5.2 ftell和rewind六、文件读取结束的判定七、文件缓冲区 一、为什…

基于 JDBC 的后端与 MySQL 数据库交互 javaweb

一、了解JDBC 二、添加MySQL的JDBC驱动包 三、使用JDBC连接数据库应用&#x1f517; 3.1创建一个包 3.2 查找实例 3.3 修改添加删除实例 四、封装 &#x1f4e6; DBConnection.java MysqlUtil.java 测试使用一下 测试1 测试2 在后端开发中&#xff0c;与数据库进行交…

贪心算法--

1.柠檬水找零 link:860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; code class Solution { public:bool lemonadeChange(vector<int>& bills) {// 贪心算法&#xff0c; 优先花出大面额bill&#xff0c; 尽可能保护小面额billint five 0, ten 0;// 不…

基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

github生成badges的方法

在Github页面上生成类似下面这样的badge的方法 你可以通过以下步骤在GitHub个人主页的README中创建类似的技术栈徽章&#xff1a; 一、使用 Shields.io 生成徽章 Shields.io 是一个开源徽章生成工具&#xff0c;支持自定义文本、颜色、图标等参数。 1. 基础模板 https://…

vue3 二次封装uni-ui中的组件,并且组件中有 v-model 的解决方法

在使用uniappvue3开发中&#xff0c; 使用了uni-ui的组件&#xff0c;但是我们也需要自定义组件&#xff0c;比如我要自定一个picker 的组件&#xff0c; 是在 uni-data-picker 组件的基础上进行封装的 父组件中的代码 <classesselect :selectclass"selectclass"…

爬虫案例七Python协程爬取视频

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Python协程爬取视频 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 爬虫案例七协程爬取视频 提示&#xff1a;以下是本篇文章正文…

Python 爬虫实战案例 - 获取拉勾网招聘职位信息

引言 拉勾网&#xff0c;作为互联网招聘领域的佼佼者&#xff0c;汇聚了海量且多样的职位招聘信息。这些信息涵盖了从新兴科技领域到传统行业转型所需的各类岗位&#xff0c;无论是初出茅庐的应届生&#xff0c;还是经验丰富的职场老手&#xff0c;都能在其中探寻到机遇。 对…

LM Studio 替换源的方式解决huggingface.co无法访问的问题

安装软件完成之后&#xff0c;不要打开&#xff0c;打开了就直接关闭 在安装目录下&#xff0c;比如我安装在E:\Program Files\LM Studio 下面三个文件中的huggingface.co全部替换为hf-mirror.com然后再打开即可。 E:\Program Files\LM Studio\resources\app\.webpack\rende…

【模拟CMOS集成电路设计】带隙基准(Bandgap)设计与仿真(基于运放的电流模BGR)

【模拟CMOS集成电路设计】带隙基准&#xff08;Bandgap&#xff09;设计与仿真 前言工程文件&部分参数计算过程&#xff0c;私聊~ 一、 设计指标指标分析&#xff1a; 二、 电路分析三、 仿真3.1仿真电路图3.2仿真结果(1)运放增益(2)基准温度系数仿真(3)瞬态启动仿真(4)静态…

微服务拆分-远程调用

我们在查询购物车列表的时候&#xff0c;它有一个需求&#xff0c;就是不仅仅要查出购物车当中的这些商品信息&#xff0c;同时还要去查到购物车当中这些商品的最新的价格和状态信息&#xff0c;跟购物车当中的快照进行一个对比&#xff0c;从而去提醒用户。 现在我们已经做了服…

P2P中NAT穿越方案(UDP/TCP)(转)

转自&#xff1a;P2P中NAT穿越方案&#xff08;UDP/TCP&#xff09;_udp反向链接-CSDN博客 同&#xff1a;P2P中NAT穿越方案&#xff08;UDP/TCP&#xff09; - 知乎 (zhihu.com) 本文介绍了传统基于udp的打洞方式&#xff0c;更进一步阐述了tcp打洞的原理&#xff0c;是对于…