Java并发编程实战读书笔记二
第五章 基础构建模块
5.1 同步容器类
5.1.1 同步容器类的问题
如下,如果list含有10个元素,线程A调用getLast的同时线程B调用deleteLast,那么getLast可能会报ArrayIndexOutOfBoundsException
改为如下方式能确保size和get一致
Vector迭代也可能引发异常
改进后的方式安全了,但降低了并发性
5.1.3 隐藏迭代器
如下可能抛出ConcurrentModificationException,以内printn ……+set 这步操作会对set进行迭代,那么在并发调用addTenThings情况下,可能出现线程A迭代set,线程B修改set的情况,所以报出ConcurrentModificationException
5.2.1 ConcurrentHashMap
采用分段锁、吞吐性能更高
5.4 阻塞方法与中断方法
当A线程发送中断信号给到B线程,B线程可以选择向上层传递或者在catch块恢复中断状态(catch后中断状态会被重置回原来的状态),让上层代码能看到这个状态
5.5 同步工具类
同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。阻塞队列可以作为同步工具类,其他类型的同步工具类还包括信号量 (Semaphore)、栅栏(Barrier)以及闭锁 (Latch)。
5.5.1 闭锁
CountDownLatch
CountDownLatch用法,测试N个线程并发执行某个任务时需要的时间。
public class TestHarness {public static void main(String[] args) throws InterruptedException {timeTasks(10,null);}public static long timeTasks(int nThreads, final Runnable task) throws InterruptedException {final CountDownLatch startGate = new CountDownLatch(1);final CountDownLatch endGate = new CountDownLatch(nThreads);for (int i = 0;i<nThreads;i++){Thread t = new Thread(() -> {try {startGate.await();try {//task.run();System.out.println("countDown测试");} finally {endGate.countDown();}} catch (InterruptedException e) {//throw new RuntimeException(e);}});t.start();}long start = System.nanoTime() ;System.out.println("start:"+start);startGate.countDown();endGate.await();long end = System.nanoTime ();System.out.println("end:"+end);return end-start;}
}
5.5.2 FutureTask也可用作闭锁
通过Callable实现,相当于一种可生成结果的Runnable。FutureTask没完成的话get()方法会阻塞
public class Preloader {public static void main(String[] args) throws InterruptedException{Preloader preloader=new Preloader();preloader.start();System.out.println("调用get方法");preloader.get();}private final FutureTask<ProductInfo> future =new FutureTask(new Callable<ProductInfo>() {public ProductInfo call() {return loadProductInfo();}});private final Thread thread = new Thread(future);public void start() {thread.start();}public ProductInfo get() throws InterruptedException {try {ProductInfo productInfo = future.get();System.out.println("得到future返回:"+productInfo);return productInfo;} catch (ExecutionException e) {Throwable cause = e.getCause();return null;}}public ProductInfo loadProductInfo () {try {Thread.sleep(10000);} catch (InterruptedException e) {throw new RuntimeException(e);}return null;}
}class ProductInfo {}
Callable表示的任务可以抛出异常或者Error,这些异常都会被封装为 ExecutionException,作为Throwable类返回
public class Preloader {public static void main(String[] args) throws InterruptedException{Preloader preloader=new Preloader();preloader.start();System.out.println("调用get方法");preloader.get();}private final FutureTask<ProductInfo> future =new FutureTask(new Callable<ProductInfo>() {public ProductInfo call() throws NumberFormatException{return loadProductInfo();}});private final Thread thread = new Thread(future);public void start() {thread.start();}public ProductInfo get() throws InterruptedException {try {ProductInfo productInfo = future.get();System.out.println("得到future返回:"+productInfo);return productInfo;} catch (ExecutionException e) {Throwable cause = e.getCause();System.out.println("获取异常");e.printStackTrace();return null;}}public ProductInfo loadProductInfo () throws NumberFormatException{try {Integer.valueOf("a");Thread.sleep(10000);} catch (InterruptedException e) {throw new RuntimeException(e);}return null;}
}class ProductInfo {}
5.5.3 信号量Semaphore
用于控制同时访问某个特定资源的操作数量、互斥锁、连接池、将容器变成有界阻塞容器
5.5.4 栅栏CyclicBarrier
转载自:CyclicBarrier 使用详解 - 简书
1. CyclicBarrier 是什么?
从字面上的意思可以知道,这个类的中文意思是“循环栅栏”。大概的意思就是一个可循环利用的屏障。
它的作用就是会让所有线程都等待完成后才会继续下一步行动。
举个例子,就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。
2. 怎么使用 CyclicBarrier
2.1 构造方法
public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
解析:
- parties 是参与线程的个数
- 第二个构造方法有一个 Runnable 参数,这个参数的意思是最后一个到达线程要做的任务
2.3 基本使用
2.3.1 需求
一个线程组的线程需要等待所有线程完成任务后再继续执行下一次任务
2.3.2 代码实现
public class CyclicBarrierDemo {static class TaskThread extends Thread {CyclicBarrier barrier;public TaskThread(CyclicBarrier barrier) {this.barrier = barrier;}@Overridepublic void run() {try {Thread.sleep(1000);System.out.println(getName() + " 到达栅栏 A");barrier.await();System.out.println(getName() + " 冲破栅栏 A");Thread.sleep(2000);System.out.println(getName() + " 到达栅栏 B");barrier.await();System.out.println(getName() + " 冲破栅栏 B");} catch (Exception e) {e.printStackTrace();}}}public static void main(String[] args) {int threadNum = 5;CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " 完成最后任务");}});for(int i = 0; i < threadNum; i++) {new TaskThread(barrier).start();}}}
打印结果:
Thread-1 到达栅栏 A
Thread-3 到达栅栏 A
Thread-0 到达栅栏 A
Thread-4 到达栅栏 A
Thread-2 到达栅栏 A
Thread-2 完成最后任务
Thread-2 冲破栅栏 A
Thread-1 冲破栅栏 A
Thread-3 冲破栅栏 A
Thread-4 冲破栅栏 A
Thread-0 冲破栅栏 A
Thread-4 到达栅栏 B
Thread-0 到达栅栏 B
Thread-3 到达栅栏 B
Thread-2 到达栅栏 B
Thread-1 到达栅栏 B
Thread-1 完成最后任务
Thread-1 冲破栅栏 B
Thread-0 冲破栅栏 B
Thread-4 冲破栅栏 B
Thread-2 冲破栅栏 B
Thread-3 冲破栅栏 B
从打印结果可以看出,所有线程会等待全部线程到达栅栏之后才会继续执行,并且最后到达的线程会完成 Runnable 的任务。
3. CyclicBarrier 使用场景
可以用于多线程计算数据,最后合并计算结果的场景。
4. CyclicBarrier 与 CountDownLatch 区别
- CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
- CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。
5.6 构建高效且可伸缩的结果缓存
第六章 任务执行
6.1 在线程中执行任务
6.2.3 线程池
在线程池中执行任务比“为每个任务分配一个线程”优势更多。通过重用现有的线程而不是创建新线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销。另一个额外的好处是,当请求到达时,工作线程通常已经存在,因此不会由于等待创建线程而延迟任务执行,提高了响应性。通过适当调整线程池的大小,可以创建足够多的线程以便使处理器保持忙碌状态,同时还可以防止过多线程相互竞争资源而使应用程序耗尽内存或失败。
newFixedThreadPool。newFixedThreadPool将创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化(如果某个线程由于发生了未预期的 Exception 而结束,那么线程池会补充一个新的线程)。
newCachedThreadPool。newCachedThreadPool将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线
程,线程池的规模不存在任何限制。
newSingleThreadExecutor。newSingleThreadExecutor是一个单线程的 Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来替代。newSingleThreadExecutor能确保依照任务在队列中的顺序来串行执行(例如 FIFO、LIFO优先级)。
newScheduledThreadPool。newScheduledThreadPool 创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于 Timer
newWorkStealingPool://todo
6.2.4 Executor的生命周期
JVM 只有在所有(非守护)线程全部终止后才会退出。因此,如果无法正确地关闭 Executor,那么JVM 将无法结束。
6.3.2 携带结果的任务 Callable 与 Future
要使用 Callable 来表示无返回值的任务,可使用 Callable<Void>
Executor 执行的任务有 4 个生命周期阶段:创建、提交、开始和完成
get 方法的行为取决于任务的状态(尚未开始、正在运行、已完成)。如果任务已经完成,那么 get 会立即返回或者抛出一个 Exception,如果任务没有完成,那么get 将阻塞并直到任务完成。如果任务抛出了异常,那么 get 将该异常封装为 ExecutionException 并重新抛出。如果任务被取消,那么get 将抛出 CancellationException。如果 get 抛出了 ExecutionException,那么可以通过 getCause 来获得被封装的初始异常。
future.cancle(true) 取消任务
使用future等待图像下载
6.3.5 CompletionService;Executor 与 BlockingQueue
采用CompletionService实现边下载图片边加载图片的功能(下载好一个图片就加载一个图片),内部实现采用了队列
6.3.7为任务设置时限
线程任务执行超时直接取消,通过future.get()设置超时时间
使用invokeAll提交一组任务,返回一组结果List<Future>
Java并发编程实战读书笔记二相关推荐
- Java并发编程实战读书笔记
Java并发编程 标签(空格分隔): 并发 多线程 基础 线程 在执行过程中,能够执行程序代码的一个执行单元,在Java语言中,线程有四种状态:运行,就绪,挂起,结束. 并发特性 原子性 一个操作不会 ...
- Java并发编程实战读书笔记三
第七章 取消和关闭 Java没有提供任何机制来安全的终止线程,虽然 Thread.stop 和 suspend 等方法提供了这样的机制,但由于存在着一些严重的陷,因此应该避免使用 7.1任务取消 7. ...
- Java并发编程实战读书笔记(一)——线程安全性、对象共享
一.线程安全性 一个对象是否需要是线程安全的,取决于它是否被多个线程访问. 当多个线程访问,并且其中有一个执行写入时,必须采用同步机制,Java中主要的同步关键字是 synchronized 独占加锁 ...
- Java并发编程实战读书笔记一
第1章 简介 第2章 线程安全性 1个状态变量线程安全的模式 多个状态变量线程不安全的模式,在A线程lastNumbers.set和lastFactors.set之间B线程进行这两个set就出问题了, ...
- java并发编程实践 读书笔记_Java - 并发编程实践(读书笔记)
[注] 同步机制保证:1)原子性 2)内存可见性: Volatile变量只能保证:1)可见性: - 恰当的同步,同步的弱形式,确保对一个变量的更新以可预见的方式告知其他线程. [注] 用锁来协调访问变 ...
- Java并发编程艺术----读书笔记(二)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a724888/article/details/64214595 java并发编程艺术2 jav ...
- Java 并发编程艺术 读书笔记
第 1 章 并发编程的挑战 1.1.3 如何减少上下文切换 减少上下文切换的方法有无锁并发编程.CAS 算法.使用最少线程和使用协程. 无锁并发编程.多线程竞争锁时,会引起上下文切换,所以多线程处理数 ...
- JAVA并发编程艺术读书笔记(1,2章节)
第一章 并发编程的挑战 为什么要使用并发编程? 主要是为了更有效地利用资源.即使是单核的CPU也可以多线程执行程序,多线程实际上是CPU分配时间片给各个线程,因为时间片非常短,所以看起来就像在同事执行 ...
- Java并发编程艺术读书笔记
1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...
最新文章
- 前端的单页面模式和多页面模式
- Leetcode 746. Min Cost Climbing Stairs
- hdu 1026 bfs+记录路径
- 一个关于Integer的秘密
- 两平面平行方向向量关系_立体几何平行证明的四大必杀绝技------赞!很赞!!非常赞!!!...
- Oracle DBA课程系列笔记(16)
- oracle orm 实例 java_Oracle数据库的JDBC查询实例
- 伪代码 嵌套循环_大学开始,跟着别人的代码敲对自己编程提高有用吗?
- 免费手机号码归属地API查询接口和PHP使用实例分享
- Unix NetWork Programming——环境搭建(解决unp.h等源码编译问题)(转载)
- NAS远程共享存储NFS
- AI早教产业鄙视链,你处在哪一层?
- 韩国NF(耐福)数字音频功放芯片系列大全
- 正则表达式——常用量词
- android web 爬虫,Android学习——Jsoup实现网络爬虫,爬取贤集网
- IntelliJ inspection gives “Cannot resolve symbol“ but still compiles code
- 外包公司的客户应该如何写需求文档?
- 启示录:TOD分类及用地功能结构组成
- 易经读书笔记15地山谦
- 2021年全球透皮贴剂收入大约6989.7百万美元,预计2028年达到8859.9百万美元
热门文章
- turtle画七彩雨伞
- easyu-tree的数据sql
- c语言中运算符的读音是什么,操作符、运算符,operator,音标,读音,翻译,英文例句,英语词典...
- 龙尚 U9300C wvdial 拨号上网
- 小码王(洛谷)怪盗基德的滑翔翼
- 计算机组成原理学习笔记第6章中央处理器CPU 6.2——数据通路DataPath
- 国家开放大学计算机专业英语翻译,中国各类基金资助项目英文翻译(中英文对照)...
- 基于esp32/8266语音门铃对讲机系统设计语音传输实时udp,espnow传输图像
- 中国土壤学会土壤生物与土壤健康研讨会(4月16-18日,杭州)
- 应用宝apk_【小镇狼人杀】新角色猜测(末尾附上应用宝下载渠道)