java并发编程实战阅读总结(b)
5、Executor框架
Executor框架是并发集合java.util.concurrent中的一个成员。
Executor为灵活且强大的异步任务执行框架提供了基础,还提供了对生命周期的支持,以及统计信息、应用管理机制和性能监视等机制。
Executor 最早是为了解决生产者-消费者模式而引入的。提交任务相当是生产者,执行任务相当是消费者。
线程池:(翻译的文档):
线程池和工作者队列密切相关,工作者线程的任务:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。
Executors类里面提供了一些静态工厂,生成一些常用的线程池。
newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
newSingleThreadScheduledExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。
线程池Executor任务拒绝策略(翻译的文档):
java.util.concurrent.RejectedExecutionHandler描述的任务操作。
第一种方式直接丢弃(DiscardPolicy)
第二种丢弃最旧任务(DiscardOldestPolicy)
第三种直接抛出异常(AbortPolicy)
第四种任务将有调用者线程去执行(CallerRunsPolicy)
生命周期(翻译的文档):
java.util.concurrent.ExecutorService 接口对象来执行任务,该接口对象通过工具类java.util.concurrent.Executors的静态方法来创建。 Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
ExecutorService扩展了Executor并添加了一些生命周期管理的方法。一个Executor的生命周期有三种状态,运行 ,关闭 ,终止。
Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,
不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true。
shutdown():执行平缓的关闭过程,不再接受新的任务,同时等待已经提交的任务执行完成。
shutdownNow();执行粗暴的关闭过程,尝试取消所有运行中的任务,并且不再启动队列中尚未开始启动的任务。
awaitTermination: 这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。
这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。
ExecutorService service = Executors. newFixedThreadPool(3);
for ( int i = 0; i < 10; i++) {
System. out.println( "创建线程" + i);
Runnable run = new Runnable() {
@Override
public void run() {
System. out.println( "启动线程");
}
};
// 在未来某个时间执行给定的命令
service.execute(run);
}
// 关闭启动线程
service.shutdown();
// 每隔1秒监测一次ExecutorService的关闭情况.
service.awaitTermination(1, TimeUnit. SECONDS);
System. out.println( "all thread complete");
System. out.println(service.isTerminated());
6、锁机制引入的死锁、活锁和饥饿
加锁机制的目的是保证线程安全,但如果过度使用锁,会导致死锁等。我们使用线程池和信号量来限制对资源的限制。但这些被限制的行为可能导致死锁。
死锁:进程之间互相争夺资源导致系统无法向前运行的一种僵死状态,如果没有外力作用下系统很难继续向前运行。请参考我的博客多线程。
饥饿:当线程无法访问到它所需要的资源而不能继续执行时,就会发生饥饿。引发饥饿的最常见资源就是CUP的时钟周期。
活锁:liveLock是进程的状态还在发生变化但是不再继续向前运行的状态。
7、线程的开销:
(1)、上下文切换。cpu在做线程切换的时候,需要保存当前线程执行的上下文,并且新调度进来的线程执行上下文设置为当前上下文。
发生越多的上下文切换,增加了调度开销,并因此降低吞吐量。
(2)、内存数据的同步。synchronized发生隐式锁竞争的地方带来的开销会影响其它线程的性能。
(3)、阻塞。当在锁上发生竞争时,竞争失败的线程会阻塞,即所谓的竞态条件。JVM通过循环不断的尝试获取锁,直到成功。或者通过操作系统挂起阻塞的线程。
如果时间短,采用等待方式,如果时间长才适合采用线程挂起的方式。串行操作降低可伸缩性,并行切换上下文也会降低性能。
在锁发生竞争时,会同时导致上面两种问题,因此,减少锁的竞争能够提高性能和收缩性。在并发程序中,
对可伸缩性最主要的威胁就是独占方式的资源锁。两个因素将影响锁上面发生竞争的可能性:锁的请求频率以及每次持有该锁的时间。
如果两者的乘积很小,那么大多数获取锁操作都不会发生竞争。
三种方式可以降低锁的竞争程度:
(1)、降低锁的请求频率。
降低线程请求锁的频率,可以通过锁分解和锁分段等技术来实现。即减小锁的粒度。如果一个锁同时需要保护好几个状态变量,那么可以把这个锁分解成多个锁,并且每个锁只保护一个状态变量,从而提高可伸缩性,并最终降低每个锁的请求频率。但是使用的锁越多,发生死锁的风险也会越高。
(2)、减少锁的持有时间。
减少被锁部分的加锁时间。缩小锁的范围(快进快出),可以将一些与锁无关的代码移出同步代码块,尤其是开销较大的操作,以及可能被阻塞的操作,比如I/O 操作。
(3)、减少使用独占锁,并发容器,读-写锁,不可变对象以及原子变量。
独占锁是一种悲观的技术。它假设最坏的情况发生(如果不加锁,其它线程会破坏对象状态),即使没有发生最坏的情况,仍然用锁保护对象状态
8、原子变量
原子性
采用锁技术会导致对锁的竞争导致系统性能降低。 当一个线程正在等待锁时,它不能做任何其他事情。如果一个线程在持有锁的情况下被延迟执行,那么所有需要这个锁的线程都无法执行下去。
原子性是指cpu在执行每一段代码时是不能被中断的。对除了long和double的基本类型的数据的简单操作都是原子的。例如a = 1; return a;
原子变量支持不用锁保护就能原子性更新操作,其底层用CAS实现。
一共有12个原子变量,可分为4组:标量类、更新器类、数组类以及复合变量类。
最常用的原子变量就是标量类:AtomicInteger、AtomicLong、AtomicBoolean以及AtomicReference。所有类型都支持CAS。
JVM对CAS的支持
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
CAS典型使用模式是:首先从V中读取A,并根据A计算新值B,然后再通过CAS以原子方式将V中的值由A变成B(只要在这期间没有任何线程将V的值修改为其他值)。
转载的博文:http://blog.csdn.net/csujiangyu/article/details/44002463
说明比较并交换的行为(而不是性能)的代码:
public class SimulatedCAS {
private int value;
public synchronized int getValue() { return value; }
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (value == expectedValue)
value = newValue;
return oldValue;
}
}
使用比较并交换实现计数器:
public class CasCounter {
private SimulatedCAS value;
public int getValue() {
return value.getValue();
}
public int increment() {
int oldValue = value.getValue();
while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
oldValue = value.getValue();
return oldValue + 1;
}
}
非阻塞同步机制
非阻塞算法的定义:一个线程的失败或者挂起,不会影响其它线程的失败或者挂起。
非阻塞算法提供比synchronized机制更高的性能和可收缩性。可以使多个线程在竞争相同的数据时候不会发生阻塞。
基于锁的算法中可能会出现各种活跃性的障碍,比如I/O 阻塞,导致其它线程都无法进行下去,导致性能下降。
java并发编程实战阅读总结(b)相关推荐
- java并发编程实战阅读总结(a)
1.锁(lock)与volatile (1).隐式锁,java提供了强制原子性的内置锁机制:synchronized块或synchronized方法. 操作共享状态的复合操作必须是原子的,以避免竞态条 ...
- 第十一章 性能与可伸缩性 Java并发编程实战 阅读总结
线程的最主要目的是提高程序的运行性能. 线程可以使程序更加充分地发挥系统的可用处理能力, 从而提高系统的资源利用率. 此外, 线程还可以使程序在运行现有任务的情况下立即开始处理新的任务, 从而提高系统 ...
- 前置条件,不变性条件,后置条件 --《java并发编程实战》
阅读<java并发编程实战>4.1.1章 收集同步需求时, 反复出现了"不变性条件","不可变条件","后验条件",令我一头雾水 ...
- Java并发编程实战笔记2:对象的组合
设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...
- aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...
- java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...
[Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...
- Java并发编程实战————恢复中断
中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作. 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupte ...
- Java并发编程实战————Executor框架与任务执行
引言 本篇博客介绍通过"执行任务"的机制来设计应用程序时需要掌握的一些知识.所有的内容均提炼自<Java并发编程实战>中第六章的内容. 大多数并发应用程序都是围绕&qu ...
- Java并发编程实战————Semaphore信号量的使用浅析
引言 本篇博客讲解<Java并发编程实战>中的同步工具类:信号量 的使用和理解. 从概念.含义入手,突出重点,配以代码实例及讲解,并以生活中的案例做类比加强记忆. 什么是信号量 Java中 ...
最新文章
- 如何搭建亿级社交信息分享社交平台架构
- 谷歌程序员少输一个“”,差点让全球Chrome笔记本变砖
- Android Studio获得sha1码
- net.sf.json在处理json对象转换为普通java实体对象时的问题和解决方案
- 国内开源软件镜像网站大全
- Android变形(Transform)之Camera使用介绍【转】
- hdu1521 指数型母函数
- TM4C123核心板焊接须知
- c语言八数码A星算法代码解析,八数码问题c语言a星算法详细实验报告含代码解析...
- xshell添加vbs脚本
- 【开源】MagicData-RAMC :180小时中文对话式语音数据集正式发布
- Mel中级教程精华篇预告
- ubuntu18.04(Jetson)以及火狐浏览器设置终端代理和清除代理命令
- python编程游戏-9个Python编程小游戏,有趣又好玩,简直太棒了
- Multisim学习(一)电路的绘制
- 保险业的5项CX预测
- 猿链猿哥:IKO,Initial Keepsake Offering,首次纪念品发行
- agv机器人无人仓系统-仓库控制模块设计
- DGA(域名生成算法)/DNS tunnel
- codeforces contest 1166 E. The LCMs Must be Large---思维
热门文章
- JavaScript 专题之函数柯里化
- CodePlex关闭,建议迁移至GitHub
- JavaScript强化教程 —— Cocos2d-JS极速调试技巧
- static方法不能直接访问类内的非static变量和不能调用this,super语句分析
- HTML5实现Word中文字全环绕图片效果
- C#基础:Lambda表达式
- Thread.yield()和Thread.sleep(0)
- linux无法访问443端口,linux – 为什么我无法在Ubuntu上ping端口443?
- tornado学习笔记day03-响应输出
- pytorch神经网络因素预测_实战:使用PyTorch构建神经网络进行房价预测