java-CyclicBarrier、CountDownLatch、Semaphore 的用法以及 volatile 关键字的作用

CyclicBarrier、CountDownLatch、Semaphore 的用法

1. CountDownLatch(线程计数器 )

  • CountDownLatch 类位于 java.util.concurrent 包下,利用它可以实现类似计数器的功能。比如有一个任务 A,它要等待其他 4 个任务执行完毕之后才能执行,此时就可以利用 CountDownLatch来实现这种功能了。
final CountDownLatch latch = new CountDownLatch(2);
new Thread(){public void run() {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
};}.start();
new Thread(){ public void run() {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
};}.start();
System.out.println("等待 2 个子线程执行完毕...");
latch.await();
System.out.println("2 个子线程已经执行完毕");
System.out.println("继续执行主线程");
}

2. CyclicBarrier(回环栅栏-等待至 barrier 状态再全部同时执行)

  • 字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环
  • 是因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。我们暂且把这个状态就叫做barrier,当调用 await()方法之后,线程就处于 barrier 了。
CyclicBarrier 中最重要的方法就是 await 方法,它有 2 个重载版本:
  1. public int await():用来挂起当前线程,直至所有线程都到达 barrier 状态再同时执行后续任务;
  2. public int await(long timeout, TimeUnit unit):让这些线程等待至一定的时间,如果还有线程没有到达 barrier 状态就直接让到达 barrier 的线程执行后续任务。
具体使用如下,另外 CyclicBarrier 是可以重用的。
public static void main(String[] args) {
int N = 4;
CyclicBarrier barrier = new CyclicBarrier(N);
for(int i=0;i<N;i++)
new Writer(barrier).start();
}
static class Writer extends Thread{
private CyclicBarrier cyclicBarrier;
public Writer(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(5000); //以睡眠来模拟线程需要预定写入数据操作
System.out.println(" 线 程 "+Thread.currentThread().getName()+" 写 入 数 据 完
毕,等待其他线程写入完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
}catch(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println("所有线程写入完毕,继续处理其他任务,比如数据操作");
}
}
  1. Semaphore(信号量-控制同时访问的线程个数)
  • Semaphore 翻译成字面意思为 信号量,Semaphore 可以控制同时访问的线程个数,通过acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
Semaphore 类中比较重要的几个方法:
  1. public void acquire(): 用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许
    可。
  2. public void acquire(int permits):获取 permits 个许可
  3. public void release() { } :释放许可。注意,在释放许可之前,必须先获获得许可。
  4. public void release(int permits) { }:释放 permits 个许可
上面 4 个方法都会被阻塞,如果想立即得到执行结果,可以使用下面几个方法
  1. public boolean tryAcquire():尝试获取一个许可,若获取成功,则立即返回 true,若获取失败,则立即返回 false
  2. public boolean tryAcquire(long timeout, TimeUnit unit):尝试获取一个许可,若在指定的时间内获取成功,则立即返回 true,否则则立即返回 false
  3. public boolean tryAcquire(int permits):尝试获取 permits 个许可,若获取成功,则立即返回 true,若获取失败,则立即返回 false
  4. public boolean tryAcquire(int permits, long timeout, TimeUnit unit): 尝试获取 permits个许可,若在指定的时间内获取成功,则立即返回 true,否则则立即返回 false
  5. 还可以通过 availablePermits()方法得到可用的许可数目。
  • 例子:若一个工厂有 5 台机器,但是有 8 个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用。那么我们就可以通过 Semaphore 来实现:
int N = 8; //工人数
Semaphore semaphore = new Semaphore(5); //机器数目
for(int i=0;i<N;i++)
new Worker(i,semaphore).start();
}
static class Worker extends Thread{
private int num;
private Semaphore semaphore;
public Worker(int num,Semaphore semaphore){
this.num = num;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("工人"+this.num+"占用一个机器在生产...");
Thread.sleep(2000);
System.out.println("工人"+this.num+"释放出机器");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
  • CountDownLatch 和 CyclicBarrier 都能够实现线程之间的等待,只不过它们侧重点不同;CountDownLatch 一般用于某个线程 A 等待若干个其他线程执行完任务之后,它才执行;而 CyclicBarrier 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch 是不能够重用的,而 CyclicBarrier 是可以重用的。
  • Semaphore 其实和锁有点类似,它一般用于控制对某组资源的访问权限。

volatile 关键字的作用(变量可见性、禁止重排序)

  • Java 语言提供了一种稍弱的同步机制,即 volatile 变量,用来确保将变量的更新操作通知到其他线程。volatile 变量具备两种特性,volatile 变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取 volatile 类型的变量时总会返回最新写入的值。

变量可见性

  • 其一是保证该变量对所有线程可见,这里的可见性指的是当一个线程修改了变量的值,那么新的值对于其他线程是可以立即获取的。

禁止重排序

  • volatile 禁止了指令重排。比 sychronized更轻量级的同步锁

  • 在访问 volatile 变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此 volatile 变量是一种比 sychronized 关键字更轻量级的同步机制。volatile 适合这种场景:一个变量被多个线程共享,线程直接给这个变量赋值。
    在这里插入图片描述

  • 当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到 CPU 缓存中。如果计算机有多个 CPU,每个线程可能在不同的 CPU 上被处理,这意味着每个线程可以拷贝到不同的 CPUcache 中。而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache这一步。

适用场景

  • 值得说明的是对 volatile 变量的单次读/写操作可以保证原子性的,如 long 和 double 类型变量,但是并不能保证 i++这种操作的原子性,因为本质上 i++是读、写两次操作。在某些场景下可以代替 Synchronized。但是,volatile 的不能完全取代 Synchronized 的位置,只有在一些特殊的场景下,才能适用 volatile。总的来说,必须同时满足下面两个条件才能保证在并发环境的线程安全:
    1. 对变量的写操作不依赖于当前值(比如 i++),或者说是单纯的变量赋值(boolean
      flag = true)。
    2. 该变量没有包含在具有其他变量的不变式中,也就是说,不同的 volatile 变量之间,不
      能互相依赖。只有在状态真正独立于程序内其他内容时才能使用 volatile。

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

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

相关文章

Selenium环境+元素定位大法

selenium 与 webdriver Selenium 是一个用于 Web 测试的工具&#xff0c;测试运行在浏览器中&#xff0c;就像真正的用户在手工操作一样。支持所有主流浏览器 WebDriver 就是对浏览器提供的原生API进行封装&#xff0c;使其成为一套更加面向对象的Selenium WebDriver API。 使…

08-信息收集-架构、搭建、WAF等

信息收集-架构、搭建、WAF等 信息收集-架构、搭建、WAF等一、前言说明二、CMS识别技术三、源码获取技术四、架构信息获取技术五、站点搭建分析1、搭建习惯-目录型站点2、搭建习惯-端口类站点3、搭建习惯-子域名站点4、搭建习惯-类似域名站点5、搭建习惯-旁注&#xff0c;c段站点…

Python“牵手”易贝(Ebay)商品列表数据,关键词搜索ebayAPI接口数据,ebayAPI接口申请指南

Ebay平台API接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范&#xff0c; EbayAPI接口是指通过编程的方式&#xff0c;让开发者能够通过HTTP协议直接访问Ebay平台的数据&#xff0c;包括商品信息、店铺信息、物流信息等&#xff0c;从而实现Ebay平…

MediaPlayer音频与视频的播放介绍

作者&#xff1a;向阳逐梦 Android多媒体中的——MediaPlayer&#xff0c;我们可以通过这个API来播放音频和视频该类是Androd多媒体框架中的一个重要组件&#xff0c;通过该类&#xff0c;我们可以以最小的步骤来获取&#xff0c;解码和播放音视频。 它支持三种不同的媒体来源…

Spring Boot进阶(58):集成PostgreSQL数据库及实战使用 | 万字长文,超级详细

1. 前言&#x1f525; PostgreSQL是一种广泛使用的开源关系型数据库&#xff0c;具有可靠性高、性能优异、拥有丰富的数据类型和扩展等优点&#xff0c;越来越多的企业和开发者开始使用它来存储和管理数据。而Spring Boot是一种快速开发的框架&#xff0c;可以简化开发过程并提…

【业务功能篇77】微服务-OSS对象存储-上传下载图片

3. 图片管理 文件存储的几种方式 单体架构可以直接把图片存储在服务器中 但是在分布式环境下面直接存储在WEB服务器中的方式就不可取了&#xff0c;这时我们需要搭建独立的文件存储服务器。 3.1 开通阿里云服务 针对本系统中的相关的文件&#xff0c;图片&#xff0c;文本等…

Django基础3——视图函数

文章目录 一、基本了解1.1 Django内置函数1.2 http请求流程 二、HttpRequest对象&#xff08;接受客户端请求&#xff09;2.1 常用属性2.2 常用方法2.3 服务端接收URL参数2.4 QueryDict对象2.5 案例2.5.1 表单GET提交2.5.2 表单POST提交2.5.3 上传文件 三、HttpResponse对象&am…

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测(含KELM、ELM等对比)

时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09; 目录 时序预测 | MATLAB实现PSO-KELM粒子群算法优化核极限学习机时间序列预测&#xff08;含KELM、ELM等对比&#xff09;预测效果基本介绍模型介绍程序设计参…

【AWS】安装配置适用于 Eclipse 的 AWS 工具包

目录 0.环境 1.步骤 1&#xff09;安装Eclipse 2&#xff09;安装AWS工具包 ① 在这个路径下点开安装软件的界面 ② 点击【Add】打开添加窗口 ③ 输入aws的工具包地址 ④ 勾选需要的工具&#xff0c;点击【Next】 ⑤ 将要安装的工具&#xff0c;点击【Next】 ⑥ 选择接受…

当 SQL Server(mssql-jdbc) 遇上 BigDecimal

需求背景 系统对接了外部系统&#xff0c;调用外部系统的接口需要付费&#xff0c;一个接口一次调用付费 0.03 元 同一个月内&#xff0c;同一个接口最高付费 25 元 统计每个月的付费情况 需求清楚了不&#xff1f;不清楚&#xff1f; 给大家举个案例 这下明白了吧 明白了需求&…

一文速学-让神经网络不再神秘,一天速学神经网络基础-激活函数(二)

前言 思索了很久到底要不要出深度学习内容&#xff0c;毕竟在数学建模专栏里边的机器学习内容还有一大半算法没有更新&#xff0c;很多坑都没有填满&#xff0c;而且现在深度学习的文章和学习课程都十分的多&#xff0c;我考虑了很久决定还是得出神经网络系列文章&#xff0c;…

企业工程项目管理系统源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理) em

​ 工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…