-
@author riemann
-
@date 2019/07/27 23:31
*/
public class SemaphoreDemo {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
private static Semaphore semaphore = new Semaphore(10);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 连接成功,保存数据。");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + " 释放连接。");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
threadPool.shutdown();
}
}
输出结果:
pool-1-thread-2 连接成功,保存数据。
pool-1-thread-3 连接成功,保存数据。
pool-1-thread-1 连接成功,保存数据。
pool-1-thread-4 连接成功,保存数据。
pool-1-thread-6 连接成功,保存数据。
pool-1-thread-7 连接成功,保存数据。
pool-1-thread-8 连接成功,保存数据。
pool-1-thread-10 连接成功,保存数据。
pool-1-thread-5 连接成功,保存数据。
pool-1-thread-9 连接成功,保存数据。
pool-1-thread-10 释放连接。
pool-1-thread-14 连接成功,保存数据。
pool-1-thread-2 释放连接。
pool-1-thread-15 连接成功,保存数据。
pool-1-thread-9 释放连接。
pool-1-thread-12 连接成功,保存数据。
pool-1-thread-8 释放连接。
pool-1-thread-16 连接成功,保存数据。
pool-1-thread-3 释放连接。
pool-1-thread-11 连接成功,保存数据。
pool-1-thread-14 释放连接。
pool-1-thread-18 连接成功,保存数据。
pool-1-thread-18 释放连接。
pool-1-thread-19 连接成功,保存数据。
pool-1-thread-7 释放连接。
pool-1-thread-20 连接成功,保存数据。
pool-1-thread-5 释放连接。
pool-1-thread-17 连接成功,保存数据。
pool-1-thread-6 释放连接。
pool-1-thread-13 连接成功,保存数据。
pool-1-thread-13 释放连接。
pool-1-thread-21 连接成功,保存数据。
pool-1-thread-1 释放连接。
pool-1-thread-22 连接成功,保存数据。
pool-1-thread-4 释放连接。
pool-1-thread-23 连接成功,保存数据。
pool-1-thread-12 释放连接。
pool-1-thread-24 连接成功,保存数据。
pool-1-thread-22 释放连接。
pool-1-thread-25 连接成功,保存数据。
pool-1-thread-19 释放连接。
pool-1-thread-26 连接成功,保存数据。
pool-1-thread-17 释放连接。
pool-1-thread-27 连接成功,保存数据。
pool-1-thread-15 释放连接。
pool-1-thread-28 连接成功,保存数据。
pool-1-thread-11 释放连接。
pool-1-thread-30 连接成功,保存数据。
pool-1-thread-26 释放连接。
pool-1-thread-29 连接成功,保存数据。
pool-1-thread-24 释放连接。
pool-1-thread-16 释放连接。
pool-1-thread-28 释放连接。
pool-1-thread-29 释放连接。
pool-1-thread-20 释放连接。
pool-1-thread-27 释放连接。
pool-1-thread-21 释放连接。
pool-1-thread-25 释放连接。
pool-1-thread-30 释放连接。
pool-1-thread-23 释放连接。
在代码中,虽然有30个线程在执行,但是只允许10个并发执行。Semaphore的构造方法Semaphore(int permits)接受一个整型的数字,表示可用的许可证数量。Semaphore(10)表示允许10个线程获取许可证,也就是最大并发数是10。
Semaphore的用法也很简单,首先线程使用Semaphore的acquire()方法获取一个许可证,使用完之后调用release()方法归还许可证。还可以用tryAcquire()方法尝试获取许可证。
Semaphore还提供一些其他方法,具体如下:
int availablePermits():返回此信号量中当前可用的许可证数。
int getQueueLength():返回正在等待获取许可证的线程数。
boolean hasQueuedThreads():是否有线程正在等待获取许可证。
void reducePermits(int reduction):减少reduction个许可证,是个protected方法。
Collection getQueuedThreads():返回所有等待获取许可证的线程集合,是个protected方法。
Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。
下面来看一下Exchanger的应用场景:
1、Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规则得出2个交配结果。
2、Exchanger也可以用于校对工作,比如我们需要将纸制银行流水通过人工的方式录入成电子银行流水,为了避免错误,采用AB岗两人进行录入,录入到Excel之后,系统需要加载这两个Excel,并对两个Excel数据进行校对,看看是否录入一致。
package com.concurrent.util;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
-
@author riemann
-
@date 2019/07/27 23:49
*/
public class ExchangerDemo {
private static final Exchanger exchanger = new Exchanger();
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String A = “银行流水100”;// A录入银行流水数据
String B = exchanger.exchange(A);
System.out.println("A的视角:A和B数据是否一致: " + A.equals(B) +
",A录入的是: " + A + ",B录入是: " + B + “。”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
String B = “银行流水200”;// B录入银行流水数据
String A = exchanger.exchange(B);
System.out.println("B的视角:A和B数据是否一致: " + A.equals(B) +
",A录入的是: " + A + ",B录入是: " + B + “。”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
输出结果:
B的视角:A和B数据是否一致: false,A录入的是: 银行流水100,B录入是: 银行流水200。
A的视角:A和B数据是否一致: false,A录入的是: 银行流水100,B录入是: 银行流水200。
如果两个线程有一个没有执行exchange()
方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用exchange(V x,longtimeout,TimeUnit unit)
设置最大等待时长。
五、CyclicBarrier和CountDownLatch的区别
第一个区别:
- CountDownLatch 一旦被打开后就不能再次合上,也是说只要被调用了足够次数的 countDown,await 方法就会失效,它是一次性的。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
独家面经总结,超级精彩
本人面试腾讯,阿里,百度等企业总结下来的面试经历,都是真实的,分享给大家!
Java面试准备
准确的说这里又分为两部分:
- Java刷题
- 算法刷题
Java刷题:此份文档详细记录了千道面试题与详解;
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
题与详解;
[外链图片转存中…(img-SffGcA3j-1712439901240)]
[外链图片转存中…(img-w05sO2fg-1712439901240)]
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算