Java多线程-JUC-1(八)
前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。而要想用好多线程,其实是可以取一些巧的,比如JUC(好多面试官喜欢问的JUC,就是现在要讲的JUC)。JUC就是java.util.concurrent的首字母缩写,它是Java并发工具包就是中提供的各种工具类的统称,主要分为几大类:
1、同步器;
2、线程安全的容器;
3、阻塞队列;
4、一些特殊的类。
他们都有各自适合应用场景。这里是并发工具包相关类的继承结构:

下面从同步器开始。
常用的JUC同步器有四个:
1、CountDownLatch:字面意思是倒计时锁,如果有“倒计时”的需求,那么CountDownLatch是最好的工具。它还有一个别称:发令枪。可以想象一下,火箭点火发射的时候,所有设备、部门都会依次检查确认,如果全部都确认准备好了才能开始发射,也就是等倒数到指定的数字(一般是0)的时候,就开始执行预设动作;
2、Semaphore:字面意思信号量,好比红绿灯,或者就餐排队时餐馆发的数字序号,一次只允许若干个线程执行。这个在昨天的例子里面也已经演示过了,而且还是通过自定义AQS来实现的(信号量可能不太好理解,我更倾向于叫它摇号器);
3、CyclicBarrier:字面意思是屏障或者栅栏,与CountDownLatch比较像,但它侧重于工作本身,即指定的若干个工作都满足考核标准(某个屏障)之后,才能继续进行下面的工作,且可反复使用;
4、Exchanger:用于线程之间交换数据,更形象地说法是“交换机”,即当一个线程完成某项工作后想与另一个线程交换数据,就可以使用这个工具类。
下面来一个个地演示它们的用法。
一、CountDownLatch
CountDownLatch的功能如果用图来表示的话,就会是这样的:

CountDownLatch实例代码:
/**
* 发令枪
*/
public class CountDownLatchTester implements Runnable {
static final CountDownLatch latch = new CountDownLatch(10);
@Override
public void run() {
// 检查任务
try {
System.out.println(Thread.currentThread().getName() + " 检查完毕!");
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
}
} public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 10; i > 0; i--) {
Thread.sleep(1000);
executor.submit(new CountDownLatchTester());
System.out.println(i);
} Thread.sleep(1000);
// 检查
latch.await(); System.out.println();
System.out.println("点火,发射!");
// 关闭线程池
executor.shutdown();
}
}
执行CountDownLatch的效果是:

二、Semaphore
Semaphore的功能如果用图来表示的话,就会是这样的:

Semaphore实例代码:
/**
* 信号量(摇号器)
*/
public class SemaphoreTester implements Runnable {
static final Semaphore semaphore = new Semaphore(3); @Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 开始进餐");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
semaphore.release();
} public static void main(String[] args) {
ExecutorService excutor = Executors.newFixedThreadPool(15);
for (int i = 0; i < 15; i++) {
excutor.submit(new SemaphoreTester());
}
excutor.shutdown();
}
}
Semaphore执行后的效果是:

三、CyclicBarrier
CyclicBarrier的功能如果用图来表示的话,就会是这样的:

CyclicBarrier实例代码:
/**
* 栅栏
*/
public class CyclicBarrierTester implements Runnable {
private final static CyclicBarrier barrier = new CyclicBarrier(3); @Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 已达到预定位置,等待指令...");
// 只有最后一个线程执行后,所有的线程才能执行2
barrier.await();
Thread.sleep(1000);
// 2 所有线程都会执行的动作
System.out.println(Thread.currentThread().getName() + " 已突破第一道封锁线");
} catch (Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 15; i++) {
executor.submit(new CyclicBarrierTester());
}
// 关闭线程池
executor.shutdown();
}
}
CyclicBarrier执行后的效果是:

四、Exchanger
Exchanger的功能如果用图来表示的话,就会是这样的:

Exchanger实例代码:
/**
* 交换机
*/
public class ExchangerTester implements Runnable {
Exchanger<Object> exchanger = null;
Object object = null; public ExchangerTester(Exchanger<Object> exchanger, Object object) {
this.exchanger = exchanger;
this.object = object;
} @Override
public void run() {
try {
Object previous = this.object;
this.object = this.exchanger.exchange(this.object);
System.out.println(Thread.currentThread().getName() + " 用对象 " + previous + " 换对象 " + this.object);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
Exchanger<Object> exchanger = new Exchanger<Object>();
ExchangerTester tester1 = new ExchangerTester(exchanger, "A");
ExchangerTester tester2 = new ExchangerTester(exchanger, "B"); new Thread(tester1).start();
new Thread(tester2).start();
}
}
Exchanger执行后的效果是:

把这四种同步器掌握好(包括它们的组合使用),几乎可以解决90%以上的使用多线程的场景问题,再也不用担心不会多线程了。
Java多线程-JUC-1(八)的更多相关文章
- Java 多线程基础(八)线程让步
Java 多线程基础(八)线程让步 yield 一.yield 介绍 yield()的作用是让步.它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权:但是,并 ...
- Java多线程学习(八)线程池与Executor 框架
目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...
- Java多线程JUC
1. volatile 关键字 多线程访问的时候,一个比较严重的问题就是内存不可见,其实在内存访问的时候每一个线程都有一个自己的缓冲区,每次在做修改的时候都是从主存取到数据,然后放到自己的缓冲区中,在 ...
- java多线程----JUC集合”01之 框架
java集合的架构.主体内容包括Collection集合和Map类:而Collection集合又可以划分为List(队列)和Set(集合). 1. List的实现类主要有: LinkedList, A ...
- Java多线程—JUC原子类
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
随机推荐
- acwing算法提高课程笔记—数字三角形模型,最长上升子序列模型
转自自网络,仅作为学习使用 1015摘花生 /*Hello Kitty想摘点花生送给她喜欢的米老鼠. 她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来. 地里每个道路的交叉点上都 ...
- AtCoder Regular Contest 116 (A~F补题记录)
补题链接:Here 第一次打 ARC,被数学题虐惨了 赛后部分数学证明学习自 ACwisher A - Odd vs Even \(T(1≤T≤2×10^5)\)组测试数据,每次询问一个正整数 \(N ...
- <vue 基础知识 6、条件判断标签v-if>
代码结构 一. 01-v-if用法 1.效果 根据分数的不同展现不同的汉字 2.代码 01-v-if用法.html <!DOCTYPE html> <html lang=&q ...
- node知识点及第三方模块
1. 读文件内容 // 1. 通过模块的名字fs对模块进行引用 const fs = require('fs'); // 2. 通过模块内部的readFile读取文件内容 fs.readFile('. ...
- Canvas原生绘制树状结构拓扑图
其实当前Web库实现Canvas绘制树状结构的组件很多,而且功能也很强大,但是难免有些场景无法实现需要自己开发,本文主要是提供一种思路 先附一个不错的拓扑图开发地址:https://www.zhihu ...
- Feign 实现微服务调用及进行服务熔断与降级
本文为博主原创,未经允许不得转载: 1. Feign 日志级别配置 2. Feign client 封装调用 3. Feign 定义熔断降级方法 4. 通过 FallbackFactory 工厂 实现 ...
- 上下文中找不到org.springframework.boot.web.servlet.server.ServletWebServerFactory bean
1.问题 报错如下: Description: Web application could not be started as there was no org.springframework.boo ...
- Laravel - 修改时间戳
将 config/app.php文件下将timezone的值改成Asia/Shanghai即可
- [转帖]MySQL 8.0 以后的版本策略变化
https://www.modb.pro/db/1717815842220630016 产品版本变更 从2023年7月18日开始,MySQL官网出现了一个新的版本 MySQL 8.1.0,直接改变 ...
- [转帖]从小白到精通:揭秘perf工具的全部功能与操作技巧
https://zhuanlan.zhihu.com/p/664396453 目录 收起 一.引言 二.理解perf工具的基本概念 三.安装与配置perf工具 3.1.不同操作系统的perf工具安 ...