Java并发编程,介绍常用的辅助类
相关免费学习推荐:java基础教程
常用的辅助类
- 1.CountDownLatch
- 1.2.示例:班长锁门问题
- 1.2.CountDownLatch类简介:
- 1.2.1 CountDownLatch概念
- 1.2.3 CountDownLatch的用法
- 1.3.CountDownLatch案例:
- 1.4.原理总结
- 2.CyclicBarrier
- 2.1.CyclicBarrier简介
- 2.2.案例:集齐7颗龙珠召唤神龙
- 3.Semophore
- 3.1.Semophore简介
- 3.2.抢车位问题
- 3.3.原理总结
1.CountDownLatch
1.2.示例:班长锁门问题
问题描述:假如有7个同学晚上上自习,钥匙在班长手上,并且要负责锁门。班长必须要等所有人都走光了,班长才能关灯锁门。这6个同学的顺序是无序的,不知道它们是何时离开。6个同学各上各的自习,中间没有交互。假如说6个学生是普通线程,班长是主线程,如何让主线程要等一堆线程运行完了,主线程才能运行完成呢。
public class CountDownLatchDemo { public static void main(String[] args) { // TODO Auto-generated method stub for(int i=1;i<=6;i++){ new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t离开教室"); },String.valueOf(i)).start(); } System.out.println(Thread.currentThread().getName()+"\t班长关门走人"); }}
运行结果截图
最后还有三个人被锁在教师了,这样可能会发生事故,所以肯定不行的。
我们要想实现这样的效果,就是等其它线程全部走完了,主线程才能运行。就需要借助JUC中的CountDownLatch类
1.2.CountDownLatch类简介:
1.2.1 CountDownLatch概念
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
CountDownLatch说明:count计数,down倒计算,Latch开始
1.2.3 CountDownLatch的用法
某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
CountDownLatch底层构造函数源代码
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
1.3.CountDownLatch案例:
public static void main(String[] args) throws InterruptedException { //6个同学正在上自习,每个人就有一个1计数器,走1个数字减1,main线程启动,必须要等计时器从6变成0,才能开始。 CountDownLatch countDownLatch=new CountDownLatch(6); for(int i=1;i<=6;i++){ new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t离开教室"); countDownLatch.countDown(); //计算减少一个 },String.valueOf(i)).start(); } countDownLatch.await(); //班长前面需要被阻塞 System.out.println(Thread.currentThread().getName()+"\t班长关门走人"); }
运行结果截图
这里每个人何时走并不知道, 但是可以保证每次都是班长最后一个走。
1.4.原理总结
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会被阻塞。
其它线程调用countDown方法将会使计数器减1(调用countDown方法的线程不会阻塞)
当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行。
2.CyclicBarrier
2.1.CyclicBarrier简介
cyclic循环,barrier屏障。
从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。
它的作用就是会让所有线程都等待完成后才会继续下一步行动。
上面班长关门的例子是做倒计时,这里是反过来,做加法,数到多少就开始。
比如人到齐了,再开会。,举个例子,就像生活中我们会约同事一起去开会,有些同事可能会早到,有些同事可能会晚到,但是这个会议规定必须等到所有人到齐之后才会让我们正式开会。这里的同事们就是各个线程,会议就是 CyclicBarrier。
构造方法
public CyclicBarrier(int parties)public CyclicBarrier(int parties, Runnable barrierAction)
解析:
parties 是参与线程的个数
第二个构造方法有一个 Runnable 参数,这个参数的意思是最后一个到达线程要做的任务
我们通常用第二个构造函数。
2.2.案例:集齐7颗龙珠召唤神龙
public static void main(String[] args) { // TODO Auto-generated method stub CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{System.out.println("召唤神龙");}); for(int i=1;i<=7;i++){ final int tempInt=i; new Thread(()->{ System.out.println(Thread.currentThread().getName()+"\t收集到第"+tempInt+"颗龙珠"); try { //某个线程收集到了龙珠只能先等着,等龙珠收齐了才能召唤神龙 cyclicBarrier.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },String.valueOf(i)).start();; } }
截图
3.Semophore
3.1.Semophore简介
前面讨论的问题都是多对一的问题,我们现在可以讨论多对多的问题了。
假设有7个兄弟开车上班,而现在只有4个车位。7部车并列开进4个车位,每个车停了多长时间未知,资源被占用完了。假设有一个车只停了2s,那么它走了,外面的车又可以进来了。走一个进一个,最后全部都可以进去。而semophore就是控制多线程的并发策略。
简单理解来说,Semaphore:信号量主要用于两个目的:一个是用于多个共享资源的互斥使用;另一个用于并发线程数量的控制。
Semaphore类有两个重要方法
1、semaphore.acquire();
请求一个信号量,这时候信号量个数-1,当减少到0的时候,下一次acquire不会再执行,只有当执行一个release()的时候,信号量不为0的时候才可以继续执行acquire
2、semaphore.release();
释放一个信号量,这时候信号量个数+1,
3.2.抢车位问题
public static void main(String[] args) { //模拟6部车抢3个空车位 Semaphore semaphore=new Semaphore(3);//模拟资源类,有3个空车位 for(int i=1;i<=6;i++){ new Thread(()->{ try { //谁先抢到了,谁就占一个车位,并且要把semaphore中的资源数减1 semaphore.acquire(); System.out.println(Thread.currentThread().getName()+"\t抢占到了车位"); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+"\t离开了车位"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ //释放车位 semaphore.release(); } },String.valueOf(i)).start(); } }
运行结果截图:
3.3.原理总结
在信号量上我们定义两种操作:
acquire(获取)当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量减1),要么一直等待下去,直到有线程释放信号量,或超时。
release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。
信号量主要用于两个目的:一个是用于多个共享资源的互斥使用;另一个用于并发线程数量的控制
如果把资源数从3变成1了,此时就等价于synchronized。
以上是Java并发编程,介绍常用的辅助类的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

如何在Java后端功能开发中处理并发访问?在现代互联网应用中,高并发访问是一个常见的挑战。当多个用户同时访问后端服务时,如果不正确处理并发,可能会导致数据一致性、性能和安全性等问题。这篇文章将介绍一些在Java后端开发中处理并发访问的最佳实践。1.使用线程同步Java提供了多种机制来处理并发访问,其中最常用的是线程同步。通过在关键代码块或方法前添加synch

如何在Java中使用Fork/Join框架创建并行任务?定义任务逻辑,计算结果或执行动作。创建ForkJoinPool管理并行线程。使用fork()方法提交任务。使用join()方法获取任务结果。

答案:反射机制通过反射API允许Java程序在运行时检查和修改类和对象,在Java并发中可用于实现灵活的并发机制。应用:动态创建线程。动态改变线程优先级。注入依赖。

如何解决:Java并发错误:死锁检测在多线程编程中,死锁是一个常见的问题。当两个或多个线程互相等待对方释放锁资源时,就会发生死锁。死锁会导致线程被阻塞,资源无法释放,程序无法继续执行,从而导致系统出现故障。为了解决这个问题,Java提供了死锁检测机制。死锁检测是通过检查线程之间的依赖关系和资源申请排队情况来判断是否存在死锁的,一旦发现死锁,系统可以采取相应的

阻塞队列:并发和多线程的强大工具阻塞队列是一种线程安全的队列,在并发和多线程编程中发挥着以下关键作用:线程同步:通过阻塞操作,防止争用条件和数据不一致。数据缓冲:作为数据缓冲区,缓解生产者和消费者线程速度不匹配的问题。负载平衡:控制队列中的元素数量,平衡生产者和消费者的负载。

解决Java并发竞态条件错误异常的方法竞态条件是指多个线程同时访问并修改共享资源时,最终结果的正确性受到执行顺序的影响。在Java中,当多个线程并发地访问共享资源时,如果没有正确地使用同步机制,就会出现竞态条件错误。当发生竞态条件错误时,程序可能会产生未预期的结果,甚至导致崩溃。本文将讨论如何解决Java并发竞态条件错误异常。一、使用同步机制最常见的解决竞态

如何解决:Java并发错误:线程死锁简介:在并发编程中,线程死锁是一个非常常见的问题。当多个线程在争夺资源时,若线程间发生相互等待对方释放资源的情况,就可能导致死锁。本文将介绍线程死锁的概念、产生原因,以及如何解决这个问题。线程死锁的概念当多个线程相互等待对方释放资源时,导致所有线程无法继续执行下去,形成了线程死锁。线程死锁的发生通常由于以下四个条件同时成立

CountDownLatch和CyclicBarrier都用于多线程环境,并且它们都是多线程环境的一部分。根据JavaDoc-CountDownLatch-一种允许一个或多个线程等待的同步辅助工具直到其他线程中执行的一组操作完成。CyclicBarrier-一种同步辅助工具,允许一组线程相互等待到达公共屏障点。先生。编号KeyCyclicBarrierCountDownLatch1基本允许一组线程的同步辅助全部等待彼此到达公共障碍点。一种允许一个或多个线程的同步辅助工具等待其他线程中执行的一组操
