从jdk1.5开始,java.util.concurrent提供了在并发编程中很常用的实用工具类,包括几个小的、已标准化的可扩展框架,以及一些提供有用功能的类。没有这些类,并发功能会很难实现或实现起来冗长乏味。本文将关注j.u.c中提供的四种同步器: CountDownLatch, CyclicBarrier, Semaphore, Exchanger,它们用于辅助实现一些常见的同步场景。下面将分别介绍java并发包中的每种同步器使用方法和常见场景。
一、CountDownLatch
1. 功能
用于同步多个线程的完成操作,让先完成的线程进行等待,直至所有线程完成。
2. 使用方法
1)新建CountDownLatch对象,定义总计数器latch。
2)调用await()方法,使当前线程进入等待状态。
3)调用countDown()方法,使计数器减一,当计数器降为0时,线程重新恢复运行。
3. 示例
场景: 10个同事约好周末一起去西湖游玩,先在公司集合完毕,到齐后一起出发,每人骑一辆自行车,统一在西湖集合。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchTest {
public static void main(String[] args) {
final CountDownLatch start = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(10);
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
executor.execute(new Employee(start, done));
}
start.countDown();
System.out.println("大部队已经准备出发.");
try {
done.await();
} catch (InterruptedException e) {
}
System.out.println("大部队在西湖集结完毕.");
executor.shutdown();
}
}
class Employee implements Runnable {
private CountDownLatch start;
private CountDownLatch done;
public Employee(CountDownLatch start, CountDownLatch done){
this.start = start;
this.done = done;
}
@Override
public void run() {
//到公司后等待
try {
start.await();
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread() + "从公司出发,去西湖路上.");
try {
Thread.sleep(new Random().nextInt(5000));
} catch (InterruptedException e1) {
}
//哥已经先到了
done.countDown();
}
}
二、CyclicBarrier
1. 功能
类似CountDownLatch,用于多次的同步多个线程的完成操作。
2. 使用方法
1)新建CyclicBarrier对象,定义总计数器和结束后的下一步动作。
2)调用await()方法,使当前线程进入等待;当await()方法的调用次数达到总计数器时,各等待线程恢复运行。
3. 示例
场景: 再考虑上面提到的场景,10个同事约好周末一起去西湖游玩,先在公司集合完毕;每人骑一辆自行车,在西湖集合完毕;大家再分散活动,中午在苏堤集合,一起吃午饭。如果采用CountDownLatch,需要定义三个CountDownLatch,下面演示如何使用CyclicBarrier解决这类问题。
import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
public static void main(String[] args) {
final CyclicBarrier barrier = new CyclicBarrier(10, new Runnable(){
@Override
public void run() {
System.out.println("大部队集合完毕了。");
}
});
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
final int num = i;
executor.execute(new Runnable(){
@Override
public void run() {
System.out.println("num: " + num + " 从公司出发了.");
try {
Thread.sleep(new Random().nextInt(5000));
barrier.await(); // 在西湖等待大部队
System.out.println("num: " + num + " 在西湖开始游玩.");
Thread.sleep(new Random().nextInt(5000));
barrier.await(); //等待大部队就餐
} catch (Exception e1) {
}
}
});
}
executor.shutdown();
}
}
三、Semaphore
1. 功能
一个计数信号量,用于限制可以访问某些资源的线程数目。
2. 使用方法
1)新建Semaphore对象,定义资源数目。
2)线程通过acquire()获取资源,通过release()释放资源。
3. 示例
场景: 10个同事一起去游戏机厅打游戏,但游戏机厅只有四台游戏机,下面示例说明使用Semaphore限制同时玩游戏机的同事数目。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
final Semaphore semaphore = new Semaphore(2,true);
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0; i<10; i++){
final int num = i;
executor.execute(new Runnable(){
@Override
public void run() {
System.out.println("num: " + num + " 想要打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
try {
semaphore.acquire(1);
} catch (InterruptedException e) {
}
System.out.println("num: " + num + " 开始打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
}
semaphore.release();
System.out.println("num: " + num + " 结束打游戏. 还有" + semaphore.availablePermits() + "台游戏机.");
}
});
}
executor.shutdown();
}
}
四、Exchanger
1. 功能
两个线程可以交换对象的同步点,每个线程给出对象,并接受其他线程返回时给出的对象。
2. 使用方法
1)新建Exchanger对象。
2)每个线程交换对象时,调用exchanger.exchange(),完成对象交换。
3. 示例
场景: 一黄牛最近拿到一部小米手机,想卖给一位同事,双方约好在公司门口交易,一手交钱,一手交货。
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerTest {
public static void main(String[] args) {
final Exchanger exchanger = new Exchanger();
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable(){
@Override
public void run() {
String money = "钞票";
System.out.println("同事有: " + money);
try {
String goods1 = (String) exchanger.exchange(money);
System.out.println("同事有: " + goods1);
} catch (InterruptedException e) {
}
}
});
executor.execute(new Runnable(){
@Override
public void run() {
String goods2 = "小米手机";
System.out.println("黄牛有: " + goods2);
//黄牛很忙,迟到一会
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
}
try {
String money = (String) exchanger.exchange(goods2);
System.out.println("黄牛有: " + money);
} catch (InterruptedException e) {
}
}
});
executor.shutdown();
}
}
分享到:
相关推荐
在实际项目中,合理使用J.U.C工具可以大幅提升代码的并发处理能力,降低系统复杂度,从而实现赚钱项目的高效运行。 请仔细阅读这份6页的PDF文档,深入理解J.U.C中的各个概念和工具,并结合实践进行应用,这将对你的...
AQS是一个用于构建锁和同步器的框架,自JDK 1.5版本引入以来,极大地提升了Java程序处理并发任务的能力。作为J.U.C的核心组成部分,AQS提供了一种基于FIFO(First In First Out)队列的数据结构,用于构建各种锁或...
### Java并发编程与高并发解决方案之并发容器(J.U.C) #### 并发容器J.U.C 在Java中,为了提供高性能、低延迟的并发数据结构,Java提供了多种并发容器类,这些类主要位于`java.util.concurrent`包内,通常被称为J.U...
首先,J.U.C库包含了大量的并发工具类,例如锁、原子变量、并发集合和执行器等。这些工具类极大地简化了并发程序的编写。在没有J.U.C之前,Java开发者要处理多线程环境中的数据安全问题,往往需要直接使用...
J.U.C提供了多种锁的实现,比如Lock接口及其实现ReentrantLock,提供了比synchronized更灵活的锁机制,同时AQS(AbstractQueuedSynchronizer)是实现各种锁的基础同步器,它管理着一系列的等待线程,并提供一种框架...
AbstractQueuedSynchronizer(AQS)是J.U.C中的一个核心框架,它为实现依赖于“first-in-first-out”(FIFO)等待队列的阻塞锁和相关同步器提供了一个框架。`ReentrantLock`、`Semaphore`、`CountDownLatch`等都是...
6 使用其他编辑器................................................................................................... 2.2 Linux下的G C C 编译器工具集.......................................... 19 2.2.1 ...
然而,尽管J.U.C提供了强大的并发工具,但要想真正掌握其使用并避免出现错误,还需要了解一些常见的误区和陷阱。例如,虽然锁能够保证数据的一致性,但是过度使用锁会导致性能瓶颈和死锁的风险。因此,如何恰当地...
AQS是J.U.C包下AbstractQueuedSynchronizer抽象的队列式的同步器的简称,这是一个抽象类,它定义了一套多线程访问共享资源的同步器框架,J.U.C包下的许多同步类实现都依赖于它,比如ReentrantLock/Semaphore/...
它与FX5U通过以太网和CC-LINK BASIC总线相连,可以实现精确的4轴同步控制。MR-JE-40C支持多种通讯协议,包括CC-LINK,这使得它能够无缝集成到FX5U系统中。 通信过程中,PLC通过以太网接口发送指令给伺服驱动器,...
r1 b# x1 k3 e 137.01 交叉检索redis 138.02 交叉检索redis* Y7 `1 z9 P" D% J+ E 139.03 判断交叉检索的key 140.04 redis的使用总结: C& g/ P ^; B. n8 Y6 d1 C# ^9 l 141.05 一些小问题. @( |. p' J! V5 s; Z+ E ...
│ 第011课动画编辑器的使用.rar$ N1 Y4 L$ J, g# L, c) x* T4 s* @ │ 第012课骨骼动画组件的使用.rar& G. _4 U0 u; U0 V: p% | │ 第013课mask_layout_scrollview组件的使用.rar {& g, [) W2 l0 b# t) M& V │ 第...
- **J2**:这是一个用于支持I2C ISP功能的跳线连接器,可以方便地进行固件更新或调试。 #### 三、U盘电路设计的关键节点与信号说明 - **SMD1、SMD2、SMD3、SMD4、SMD5、SMD6、SMD7**:这些是信号分配点,用于连接...
│ 11.Maven项目模块划分-引用依赖包( f- {5 L4 F2 i8 z+ c* U │ 12.项目环境搭建细节-监听器 │ 13.项目环境搭建细节-过滤器 │ 14.项目环境搭建细节-核心控制器 │ 15.项目环境搭建细节-spring-springmvc相关配置...
2. 旋转变压器和感应同步器用于位置检测,完成补偿连线可以改善信号质量。 3. 直流测速发电机的输出电压误差可能源于非线性、温度影响等因素。 4. 增量码盘使用两个光电转换器以确定方向,寻零通常在电源启动时进行...
本应用笔记旨在通过一个实际案例展示如何使用 ST7 微控制器的 SPI 外设进行通信。该文档具体阐述了如何实现 ST7 微控制器与 M95xxx 系列 SPI EEPROM 的简单数据写入与读取操作。 #### 一、ST7 与 EEPROM 的 SPI ...
- 串行工作量的减少:如同步(synchronized 和 j.u.c.Lock)和线程安全的数据结构会导致通信开销。 - 随着线程数增加的成本:上下文切换、监控工具(如JConsole、Java Mission Control、JProfiler和HealthCenter &...