《Java并发编程实战》学习笔记
captxb
这个作者很懒,什么都没留下…
展开
-
chapter14_构建自定义的同步工具_2_使用条件队列
条件队列可以构建高效、高响应性的状态依赖类(wait时自动挂起, 不用像轮询方式一样费尽心机的选择sleep时间), 但是__容易不正确使用__所以, 如果可能的话, 还是__尽可能用LinkedBlockingQueue, Latch, Semephore, FutureTask等__条件谓词(1) 定义使某个操作成为状态依赖操作的前提条件例如, BlockingQueue的t...原创 2019-03-19 14:51:26 · 151 阅读 · 0 评论 -
chapter11_性能与可伸缩性_1_对性能的思考
(1) 提升性能往往意味着增加复杂性, 因此增加了安全性和活跃性上发生失败的风险(2) 提升性能很重要, 但是安全性是第一位的__资源__常常包括CPU时钟周期内存网络带宽IO带宽数据库请求磁盘空间使用多线程__未必可以提升整体性能__, 因为使用多线程总会引入额外的开销(1) 线程之间的协调(2) 上下文切换操作(3) 线程的创建和销毁(4) 线程的调度...原创 2019-03-17 14:33:09 · 109 阅读 · 0 评论 -
chapter10_避免活跃性危险_3_其他活跃性危险
饥饿(1) 某个线程总是占有CPU或者锁, 造成其他线程总是无法得到CPU或锁(2) 常见情景1° 某个持有锁的线程中存在死循环, 或者无限制等待某个资源2° 某个线程有着高的优先级(3) 尽量避免使用线程优先级线程优先级和操作系统相关, 实际执行时的优先级未必就是程序中设置的优先级。因此有活跃性风险活锁(1) 尽管线程不会阻塞, 但是总是在相同的地方不断执行相同的操作, ...原创 2019-03-17 14:29:59 · 99 阅读 · 0 评论 -
chapter10_避免活跃性危险_2_死锁的避免与诊断
(1) 如果每次至多只能获得一个锁, 那么一定不会产生锁顺序死锁(2) 如果必须获得多个锁, 必须考虑锁的顺序:1° 尽可能减少锁的数量2° 将获取锁时需要遵循的协议规范化支持定时的锁(1) 显示锁 java.util.concurrent.Lock接口中可以指定tryLock方法的超时时限, 超时后会返回bool值而不是一直阻塞(2) 定时锁失败时, 并不需要知道失败的原因...原创 2019-03-17 14:27:36 · 133 阅读 · 0 评论 -
chapter10_避免活跃性危险_1_死锁
死锁包括了几种情况, 例如__锁顺序死锁__、动态的锁顺序死锁、协作对象间的死锁、__资源死锁__等几种情况锁顺序死锁(1) 两个线程以不同的顺序获得相同的锁, 就会引发锁顺序死锁示例 public class LeftRightDeadlock { private final Object left = new Object(); private fi...原创 2019-03-17 14:26:22 · 103 阅读 · 0 评论 -
chapter05_基础构建模块_2_并发容器
(1) 并发容器≠同步容器(2) 同步容器将所有对容器状态的访问都串行化,严重影响性能(3) 并发容器专门为多线程并发设计, 应该尽可能通过并发容器代替同步容器(4) 并发容器有 ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue, ConcurrentSkipListSet等ConcurrentHashMa...原创 2019-03-13 20:43:14 · 82 阅读 · 0 评论 -
chapter05_基础构建模块_4_阻塞方法与中断方法
和Thread.sleep一样, BlockingQueue的put和take方法会抛出编译器异常 InterruptedException; __如果一个方法抛出InterruptedException, 说明这个方法是一个阻塞方法Thread提供了interrupt(), interrupted(), isInterrupted()方法 public class Thread i...原创 2019-03-13 20:42:40 · 105 阅读 · 0 评论 -
chapter05_基础构建模块_3_阻塞队列和生产者-消费者模式
BlockingQueue接口和生产者-消费者模式(1) 生产者-消费者模式消除了生产者类和消费者类之间的代码依赖性: 生产者将数据放入队列; 消费者从队列中取数据(2) 阻塞队列提供了可阻塞的put和take方法, 和支持定时的offer和poll方法(3) 队列可以有界也可以无界(在构造函数中指定, 但其实无界的阻塞队列也有最大值Integer.MAX_VAL)(4) Blocki...原创 2019-03-13 20:21:59 · 121 阅读 · 0 评论 -
chapter05_基础构建模块_1_同步容器类
委托是创建线程安全类的一个最有效的策略, 只需让现有的线程安全类管理所有的状态即可Collections.synchronizedXXX是一些__同步容器类__, 这些类的实现方式是将它们的状态封装起来, 并且对每个公有方法都进行同步同步容器类包括 Vector, HashTable, Collections.synchronizedXXX同步容器类的问题(1) 同步容器类...原创 2019-03-13 20:07:06 · 65 阅读 · 0 评论 -
chapter04_对象的组合_4_在现有的线程安全类中添加功能
很多情况下应该重用现有的类, 添加自定义的功能, 此时需要在__不破坏线程安全性__的情况下添加新的操作(1) 方法一: 直接修改原始的类优点: 同步策略仍然处于同一个源代码文件中, 更容易理解和维护缺点: 常常无法修改源代码(2) 方法二: 扩展这个类同步策略分布到了各个文件中, 并且要确定的得知基类的同步策略示例 @ThreadSafe public class Bet...原创 2019-03-13 20:06:51 · 77 阅读 · 0 评论 -
chapter04_对象的组合_3_线程安全性的委托
(1) 从头开始构建一个类, 或将多个非线程安全的类组合为一个类时, Java监视器模式很有效(见"2_实例封闭.md");多个线程安全的类组合为一个类时, 可以考虑__委托方式__(2) 示例1° 基于监视器模式的车辆追踪MonitorVehicleTracker.java @ThreadSafe public class MonitorVehicleTracker { ...原创 2019-03-12 14:11:53 · 130 阅读 · 0 评论 -
chapter04_对象的组合_2_实例封闭
封闭(1) 封装简化了线程安全类的实现过程。将数据封装在对象内部, 可以将数据的访问限制在对象的方法上, 从而更容易确保线程在访问数据时总能持有正确的锁(2) 被封闭对象不能超出它们既定的作用域1° 可以封闭在一个类实例中(private变量)2° 可以封闭在某个作用域内(局部变量)3° 封闭在线程内(只在同一个线程的不同方法内传递, 不在不同线程间传递)可以使用对象的内置锁t...原创 2019-03-12 11:01:26 · 123 阅读 · 0 评论 -
chapter04_对象的组合_1_设计线程安全的类
设计线程安全的类的__三要素__(1) 找出构成对象状态的所有变量(2) 找出约束状态变量的不可变条件(3) 建立对象状态的并发访问管理策略如果对象的域都是基本类型, 则它们组成了对象的全部状态; 如果出现了引用类型, 则要递归的包含它们引用对象的域同步策略规定了如何在不违背对象的不变条件和后验条件的情况下对其状态的访问操作进行协同, 规定了如何将不可变性、线程封闭、加锁机...原创 2019-03-12 10:50:14 · 78 阅读 · 0 评论 -
chapter11_性能与可伸缩性_2_Amdahl定律
(1) 加速比: 同一个任务在单处理器系统和并行处理器系统中运行消耗的时间的比率加速比越大, 说明这个任务加入并行处理后执行速度提升的越明显(2) 处理器利用率: 加速比除以处理器的数量(3) Amdahl定律1° 近似的给出了在增加计算资源的情况下, 程序理论上可以实现的最高加速比2° 公式 加速比 ≤ 1 / (F + (1-F)/N)其中, F代表串行执行部分占总体的比...原创 2019-03-17 14:47:54 · 161 阅读 · 0 评论 -
chapter11_性能与可伸缩性_3_线程引入的开销
对于为了提升性能而引入的线程来说, 并行带来的性能提升必须超过并发导致的开销上下文切换(1) 如果可运行的线程数量大于CPU的数量, 那么操作系统每隔一段时间会将某个线程调度出来, 这回导致一次上下文切换(2) 应用程序、JVM、操作系统共享一组CPU, 因此切换消耗的CPU时钟周期长, 意味着留给应用程序的时钟周期短(3) 调度会为每个可运行的线程分配一个__最小执行时间__原...原创 2019-03-17 16:19:36 · 109 阅读 · 0 评论 -
chapter11_性能与可伸缩性_4_减少锁的竞争
(1) 串行操作将降低可伸缩性(2) 上下文切换会降低性能(3) 锁上发生竞争时, 将同时导致这两个问题–> 尽量减少锁的竞争影响锁竞争发生可能性的因素(1) 锁的请求频率(2) 每次持有锁的时间对应的降低锁的竞争程度的解决方案(1) 降低锁的请求频率(2) 减少锁的持有时间(3) 使用__带有协调机制__的锁接下来会介绍具体的解决办法缩小锁的范围——...原创 2019-03-17 16:24:48 · 129 阅读 · 0 评论 -
chapter14_构建自定义的同步工具_1_状态依赖性的管理
轮询方式(1) 基类 @ThreadSafe public abstract class BaseBoundedBuffer<V> { @GuardedBy("this") private final V[] buf; @GuardedBy("this") private int tail; @Guarde...原创 2019-03-19 14:51:15 · 133 阅读 · 0 评论 -
chapter13_显式锁_5_读写锁
(1) ReadWriteLock是一个接口 public interface ReadWriteLock { /** * Returns the lock used for reading. * * @return the lock used for reading */ Lock readLock(); ...原创 2019-03-18 20:46:00 · 112 阅读 · 0 评论 -
chapter13_显式锁_4_在synchronized和ReentrantLock之间选择
根据"2_性能考虑因素.md", 通过性能做出选择很不稳(1) 内置锁的优势1° 历史遗留2° 不需要显式unlock3° 线程转储中, JVM可以知道哪些线程持有哪些内置锁, 但是不知道持有哪些ReentrantLock(2) ReentrantLock的优势1° 功能丰富可定时可轮询可中断(3) 所以, 如果内置锁可以满足需求, 就用synchronized; 如果...原创 2019-03-18 20:40:27 · 84 阅读 · 0 评论 -
chapter13_显式锁_3_公平性
(1) 在ReentrantLock的构造函数中可以指定创建公平性的锁还是非公平性的锁 /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a ...原创 2019-03-18 20:05:26 · 91 阅读 · 0 评论 -
chapter13_显式锁_2_性能考虑因素
ReentrantLock和synchronized到底谁的性能好?随着Java版本的迭代, 它们之间性能比较的结果不太稳, 有的时候ReentrantLock好, 有的时候synchronized好原创 2019-03-18 20:01:48 · 82 阅读 · 0 评论 -
chapter13_显式锁_1_Lock与ReentrantLock
(1) Lock是一个接口, 它提供了一种无条件的、可轮询的、定时的、可中断的锁获取操作m 所有加锁和解锁的方法都是__显式__的 public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock();...原创 2019-03-18 19:59:30 · 89 阅读 · 0 评论 -
chapter05_基础构建模块_5_同步工具类
共同特点: 封装了一些状态, 用于决定执行同步工具类的线程继续执行还是等待常见的有闭锁、信号量、栅栏等闭锁(1) 功能: 在闭锁到达结束状态之前, 门一直关闭没有任何线程可以通过;在闭锁到达结束状态后,门会打开, 允许所有线程通过,且永远保持打开(2) 应用场景: 确保某些活动直到其他活动完成后才继续执行1° 确保某个计算在其需要的所有资源都初始化以后才执行2° 确保某个服务在...原创 2019-03-13 20:42:58 · 110 阅读 · 0 评论 -
chapter12_并发程序的测试_4_其他的测试方法
测试的目标不是为了更多的发现错误, 而是提高代码能按照预期方式工作的可信度(1) 代码审查CodeReview(2) 静态分析工具: 它们不需要运行代码, 是在分析代码中是否存在常见的错误模式, 例如FindBugs软件常见的能被静态分析出来的问题1° 不一致的同步使用了不同的锁2° 调用了Thread.run()3° 显示锁没有被释放4° 空的同步块5° 双重检查加锁...原创 2019-03-18 19:35:59 · 99 阅读 · 0 评论 -
chapter12_并发程序的测试_3_避免性能测试的陷阱
垃圾回收(1) 垃圾回收的时序无法预测所以会导致有时测出的执行时间由于GC的影响而导致不准(2) 应对GC造成的测量时间误差的策略1° 确保GC操作在测试期间不会运行用-verbose查看JVM运行时是否GC过2° 确保GC操作在测试期间执行过多次这种方式比较靠谱, 因为它比较像真实的运行环境动态编译(1) JIT技术导致测试的时间既有可能是解释执行的时间, 也有可能是编...原创 2019-03-18 19:35:50 · 250 阅读 · 0 评论 -
chapter12_并发程序的测试_2_性能测试
尽量模拟被测试对象在应用程序中的实际用法吞吐率单位时间内处理的任务数量根据P217的图, 当增加更多的线程时, 吞吐率可能会有所下降, 因为没有足够多的CPU用于计算, 大部分时间耗在了线程的阻塞和解除阻塞上面java.util.concurrent中的算法已经通过无数的测试进行了调优, 性能达到了我们已知的最佳状态, 所以要尽可能使用已有的库满足我们的需求信号量可以...原创 2019-03-18 19:35:42 · 96 阅读 · 0 评论 -
chapter12_并发程序的测试_1_正确性测试
正确性测试(0) 要测试的类SemaphoreBoundedBuffer.java @ThreadSafe public class SemaphoreBoundedBuffer<E> { private final Semaphore availableItems, availableSpaces; @GuardedBy("this") ...原创 2019-03-18 19:35:33 · 338 阅读 · 0 评论 -
chapter12_并发程序的测试_0_绪论
并发测试(1) 安全性测试安全性: 不发生任何错误的行为(2) 活跃性测试活跃性: 某个良好的行为终究会发生性能的衡量指标(1) 吞吐量一组并发任务中已完成任务所占的比例(2) 响应性请求从发出到完成之间的时间(3) 可伸缩性在增加更多资源的情况下(通常是增加CPU), 吞吐量的提升情况...原创 2019-03-18 19:35:20 · 100 阅读 · 0 评论 -
chapter03_对象的共享_5_安全发布
(1) Java内存模型为不可变对象的共享提供了特殊的初始化安全性保证, 即使在发布这些对象时没有同步(2) 在没有额外同步的情况下, 也可以保证安全访问final类型的域(但是如果final类型的域所指向的是可变对象, 还是需要同步)一个正确构造的对象, 可以通过以下方式安全发布(1) 静态初始化函数中初始化一个对象引用JVM内部存在的同步机制保证(2) 将对象的引用保存到vo...原创 2019-03-12 10:49:27 · 86 阅读 · 0 评论 -
chapter03_对象的共享_4_不变性
不可变对象(1) 满足条件1° 对象创建以后状态不能更改2° 对象的所有域都是final类型(包括对象的字段也是final)3° 对象被正确创建(构造函数中没有发生this引用逸出)(2) 不可变对象一定是线程安全的(3) 不可变对象的状态可以更新, 更新的方式是通过一个保存新状态的实例来替换原有的不可变对象(例如String, Integer)final域(1) 如果fi...原创 2019-03-12 10:46:03 · 101 阅读 · 0 评论 -
chapter03_对象的共享_3_线程封闭
(1) 访问共享的可变数据时, 通常就需要__同步__(2) 为了避免同步, 可以不共享数据, 在__单线程内__访问拘束的话就不需要共享数据, 这就叫__线程封闭__线程封闭的方式(1) Ad-hoc封闭: 完全交给程序实现者承担尽量少用这种方式(2) 栈封闭: 只能通过__局部变量__访问对象示例 public class Animals { ... ...原创 2019-03-12 10:36:03 · 95 阅读 · 0 评论 -
chapter14_构建自定义的同步工具_5_AbstractQueuedSynchronizer
(1) 在基于AQS构建的同步器类中, 最基本的操作是各种形式的__获取__操作和__释放__操作(2) 获取操作是一种__依赖状态__的操作, 并且通常会阻塞(3) 获取操作包括两个子操作:1° 同步器判断当前状态是否允许获得操作2° 更新同步器的状态各种同步器(ReentrantLock, Semaphore等)的区别其实本质上就是这两个操作的实现方式不一样(4) 释放操作不是...原创 2019-03-19 15:07:55 · 75 阅读 · 0 评论 -
chapter14_构建自定义的同步工具_4_Synchronizer剖析
(1) 很多同步工具内部都__使用了__AbstractQueuedSynchronizer(AQS)(2) 基于AQS构建同步工具可以减少实现工作, 而且不必处理在多个位置上发生的竞争问题(3) ReentrantLock, Semephore, CountDownLatch, FutureTask等内部都用到了AbstractQueuedSynchronizer的实现类...原创 2019-03-19 15:06:52 · 97 阅读 · 0 评论 -
chapter14_构建自定义的同步工具_3_显式的Condition对象
(1) Condition是一种广义的条件队列(2) 在java.util.concurrent.locks包中, Condition是一个接口 public interface Condition { void await() throws InterruptedException; void awaitUninterruptibly(); l...原创 2019-03-19 14:49:53 · 148 阅读 · 0 评论 -
chapter08_线程池的使用_2_设置线程池的大小
(1) 对于__计算密集型__的任务,在拥有Ncpu个处理器的系统上,应该把线程池大小设为Ncpu+1个,可以达到最佳利用率(2) 对于__包含IO操作__的任务,线程池的最佳规模应该大于Ncpu+1,粗略计算的公式是 N_threads = N_cpu * U_cpu * (1 + W/C)其中,N_threads代表线程池最佳规模,N_cpu代表CPU数量,U_cpu代表期望的C...原创 2019-03-14 16:13:00 · 115 阅读 · 0 评论 -
chapter08_线程池的使用_1_在任务与执行策略之间的隐性耦合
(1) Executor框架的好处是将__任务的提交__和__任务的执行策略__进行解耦(2) 但是有些情况不适合用Executor框架1° 依赖性任务一个线程中的任务依赖另一个线程中的任务或资源2° 使用线程封闭机制的任务使用newSingleThreadExecutor可以把这种任务执行的很好,但是后续的开发人员一旦不知道这件事就完蛋了3° 对响应时间敏感的任务如果任务的执行...原创 2019-03-14 16:04:38 · 150 阅读 · 0 评论 -
chapter07_取消与关闭_3_处理非正常的线程终止
任何代码都可能抛出RuntimeException,所以每当调用另一个方法时,都要对它的行为保持怀疑两种方式处理可能的非正常线程终止情况(1) 把任务套在try块中,如果抛出异常先通知一下框架该线程已经终结线程池和Swing都用了这个方法线程池__工作者线程__的伪代码 public void run() { Throwable thrown = null; ...原创 2019-03-14 14:58:37 · 159 阅读 · 0 评论 -
chapter07_取消与关闭_2_停止基于线程的服务
(1) 线程池是线程的所有者,应用程序不是线程的所有者,所以应用程序不能直接停止线程,而是交给线程池处理(2) 线程池应该提供__生命周期方法__,来关闭自己以及所拥有的线程(3) __对于持有线程的服务,只要服务的存在时间大于创建线程的方法的存在时间,那么就应该提供生命周期方法关闭ExecutorService在复杂程序中,通常会将ExecutorService封装在某个高级别的...原创 2019-03-14 14:37:53 · 115 阅读 · 0 评论 -
chapter07_取消与关闭_4__JVM关闭
JVM关闭的措施(1) 正常关闭1° 最后一个非守护线程结束2° 调用System.exit()3° 特定平台的关闭错误(例如SIGINT信号或CTRL+C)(2) 非正常关闭1° Runtime.halt()2° 操作系统中强行kill关闭钩子(1) 关闭钩子通过Runtime.addShutdownHook注册的、但是尚未开始的线程(2) 在__正常关闭__中, ...原创 2019-03-14 10:02:32 · 138 阅读 · 0 评论 -
chapter07_取消与关闭_1_任务取消
(1) 可取消的如果外部代码可以在某个操作正常完成之间就__将其置入完成状态__, 那么这个操作就是__可取消的__(2) 取消某个操作的原因1° 点击取消按钮2° 时间限制3° 并行计算, 某一部分已经得到运行结果, 其他部分需要取消4° 出现错误(例如磁盘已满)5° 服务关闭简单的取消策略示例 @ThreadSafe public class PrimeGen...原创 2019-03-14 09:56:10 · 116 阅读 · 0 评论