JUC之CountDownLatch、CyclicBarrier、Semaphore
Latch [lætʃ]
①、子线程执行完,需要调用countDown方法实现计数减一
②、主线程await进入阻塞,所有子进程结束后才会被再次唤醒执行。
③、基于Sync extends AbstractQueuedSynchronizer实现线程安全
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(6); // 初始化线程个数,子线程数可以大于初始化数
for (int i = 0; i < 7; i++) {
new Thread(()->{
System.out.println("线程:" + Thread.currentThread().getName());
countDownLatch.countDown(); // 子线程操作完,调用countDown方法实现计数减一
}, "Thread" + i).start();
}
try {
countDownLatch.await(); // 进入阻塞,子任务执行完才再一次被唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 子线程全部执行完成");
}
输出:
线程:Thread0
线程:Thread5
线程:Thread3
线程:Thread1
线程:Thread2
线程:Thread6
线程:Thread4
main 子线程全部执行完成
二、CyclicBarrier
Cyclic [ˈsaɪklɪk] Barrier [ˈbæriər]
①、构造方法CyclicBarrier(int parties, Runnable barrierAction)
|| CyclicBarrier(int parties)
②、构造方法可以提供Runnable barrierAction方法(操作屏障),并且是最后一个子线程调用该方法;
③、所有子线程进入就绪状态后,就调用Runnable barrierAction方法
④、基于ReentrantLock可重入锁和Condition来实现线程安全。
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println(Thread.currentThread().getName() + "七个线程已就绪,准备运行。。。");
});
for (int i = 0; i < 7; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "正在运行");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, "线程"+i).start();
}
}
输出:
线程3正在运行
线程0正在运行
线程5正在运行
线程4正在运行
线程6正在运行
线程1正在运行
线程2正在运行
线程2七个线程已就绪,准备运行。。。
[ˈseməfɔːr]
①、基于继承AQS的Sync实现类,以及继承Sync的FairSync和NonfairSync实现,保证执行顺序和并发量。
②、提供两种构造器:Semaphore(int permits, boolean fair)和Semaphore(int permits)。 permits为申请的资源数(队列数)。 fair=true公平锁,否在是非公平锁。
③、解决多个共享资源的互斥使用、并发线程数的控制(可替换Synchronized)
④、需要抢占acquire() [əˈkwaɪər]资源,抢占成功,资源数-1; 执行完之后需要release()释放资源资源数+1
⑤、如果permits==1,其场景类似于Synchronized
// Semaphore
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3, false); // 初始化资源数为3 采用NonFairSync非公平锁
for (int i = 0; i < 7; i++) {
new Thread(()->{
try {
semaphore.acquire();
// for(;;)循环遍历直到资源抢占成功为止
// 资源抢占成功,调用AQS的方法将资源数减一
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 抢占到了资源");
try {
TimeUnit.SECONDS.sleep(4);
System.out.println(Thread.currentThread().getName() + " 释放资源");
} catch (Exception e) {
e.printStackTrace();
}finally {
semaphore.release(); // 需要将资源加一 调用AQS的方法将资源数+1
}
}, "线程"+i).start();
}
}
线程2 抢占到了资源
线程1 抢占到了资源
线程0 抢占到了资源
线程1 释放资源
线程2 释放资源
线程4 抢占到了资源
线程3 抢占到了资源
线程0 释放资源
线程6 抢占到了资源
线程4 释放资源
线程6 释放资源
线程3 释放资源
线程5 抢占到了资源
线程5 释放资源
四、阻塞队列BlockingQueue
①、当队列满时,再添加元素add报错,IllegalStateException:Queue full;
②、当队列为空时,再移除元素remove时,会报错:IllegalStateException: NoSuchElementException
③、使用put方法当元素满时,会阻塞直到有元素减少;使用take方法,队列为空时会阻塞,直到有可取的元素;
④、offer、poll可设置超时时间,如果poll超时没有返回,返回null。
package com.cn.test.demo.testdemo.learnofJUC;
import java.util.concurrent.*;
public class BlockingQueueTest {
public static void main(String[] args) {
Basket basket = new Basket();
class Consume implements Runnable {
测试输出:
生产一个苹果:1655649340927
生产一个苹果:1655649340933
消费一个苹果:aaaa 1655649340927
size:4
消费一个苹果:produce an apple... 1655649342950
size:4
生产一个苹果:1655649342950
消费一个苹果:aaaa 1655649344963
size:3
五、死锁
概念:两个或两个以上的线程,在资源抢占过程中,造成一种互相等待且无外力没法解决的情况。
造成原因
①、资源不够 ②、进制运行推进不合适 ③、资源分配不合适
问题排查
jps -l 命令查看Java进程 然后用jstack ${pid}查看项目进程使用情况,查找定位阻塞的代码
public class DeadLockTest {
public static void main(String[] args) {
String o1 = new String("Thread-o1");
String o2 = new String("Thread-o2");
new Thread(()->{
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "加锁成功...");
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, o1).start();
new Thread(()->{
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "加锁成功...");
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("获取到o1锁...");
}
}
}, o2).start();
}
}
C:\Users\12198>jps -l
7072 org.jetbrains.jps.cmdline.Launcher
7152 org.jetbrains.idea.maven.server.RemoteMavenServer36
8232 com.cn.test.demo.testdemo.learnofJUC.DeadLockTest
11868
5436 jdk.jcmd/sun.tools.jps.Jps
C:\Users\12198>jstack 8232
2022-06-20 10:08:34
Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0.1+12-LTS-39 mixed mode, sharing):
Threads class SMR info:
_java_thread_list=0x00000232786273c0, length=15, elements={
....... //此处为省略。
解决方案
①、重启或者杀死进程。
②、修改代码,优化不合理的资源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】