Java并发实战-学习笔记
学习Java并发实战,将自己的学习笔记总结记录一下
赱乂
士不可以不弘毅,任重而道远
展开
-
AbstractQueuedSynchronizer
AQS中获取操作和释放操作的标准形式:boolean acquire() throws InterruptedException{ while(当前状态不允许获取操作){ if(需要阻塞获取请求){ 如果当前线程不在队列中,则将其插入队列 阻塞当前线程 } else ...原创 2018-06-19 08:05:03 · 127 阅读 · 0 评论 -
锁Lock与原子变量Atomic的性能比较
生成随机数的方法:public class PseudoRandom { int calculateNext(int prev) { prev ^= prev << 6; prev ^= prev >>> 21; prev ^= (prev << 7); return prev;原创 2018-06-19 08:05:33 · 3238 阅读 · 0 评论 -
比较并交换CAS
CAS包含了3个操作数—需要读写的内存位置V、进行比较的值A和拟写入的新值B。当且仅当V的值等于A时,CAS才会通过原子方式用新值B来更新V的值,否则不会执行任何操作。无论位置V的值是否等于A,都将返回V原有的值。CAS的含义是:“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际是多少。”@ThreadSafepublic class Simul...原创 2018-06-19 08:05:24 · 1014 阅读 · 0 评论 -
ConcurrentLinkedQueue中非阻塞链表的插入
在许多队列算法中,空队列通常都包含一个“哨兵(Sentinel)”或者“哑(Dummy)节点”,并且头结点和尾节点在初始化时都指向该哨兵节点。尾节点通常要么指向哨兵节点(如果队列为空),即队列的最后一个元素,要么(当有操作正在执行更新时)指向倒数第二个元素。使用哨兵节点与不使用哨兵节点的区别: 带哨兵节点的链表,需要额外的一个节点,插入或删除时,不论操作的位置,表头都不变,不需要额外的判...原创 2018-06-19 08:57:24 · 243 阅读 · 0 评论 -
使用ReentrantReadWriteLock读写锁来包装Map
当锁的持有时间较长并且大部分操作都不会修改被守护的资源时,那么读写锁能提高并发性。在ReadWriteMap中使用了ReentrantReadWriteLock来包装Map,从而使它能在多个读线程之间被安全的共享,并且仍然能避免“读写”或“写写”冲突。在现实中,ConcurrentHashMap的性能已经很好了,因此如果只需要 一个并发的基于散列的映射,那么就可以使用ConcurrentHa...原创 2018-06-17 18:03:45 · 440 阅读 · 0 评论 -
有界缓存的状态依赖优化
可阻塞的状态依赖操作的结构加锁模式不同寻常,因为锁是在操作的执行过程中被释放与重新获取的。构成前提条件的状态变量必须由对象的锁来保护,从而使它们在测试前提条件的同时保持不变。如果前提条件尚未满足,就必须释放锁,以便其他线程可以修改对象的转改,否则,前提条件就永远无法变成真。在再次测试前提条件之前,必须重新获得锁。acquire lock on object statewhile(pr...原创 2018-06-17 21:29:58 · 184 阅读 · 0 评论 -
使用显示条件变量Lock.Condition实现的有界缓存
1、wait,notify,notifyAll 同一个对象Object o,线程A调用wait方法在o的阻塞队列上进行等待a条件满足的notify通知,线程B调用wait方法在o的阻塞队列上进行等待b条件满足的notify通知。 对象o上的阻塞队列中等待的任务不是同一种类型,导致为了避免通知信号丢失,而使用notifyAll进行通知,也就是说A或者B中的某一个满足条件时,要使用notify...原创 2018-06-18 11:03:59 · 177 阅读 · 0 评论 -
使用Lock来实现信号量Semaphore
@ThreadSafepublic class SemaphoreOnLock { private final Lock lock = new ReentrantLock(); // CONDITION PREDICATE: permitsAvailable (permits > 0) private final Condition permitsAvailable...原创 2018-06-18 14:07:17 · 270 阅读 · 0 评论 -
基于信号量的有界缓存
1、使用信号量Semaphore来实现有界缓存2、代码如下:/** * BoundedBuffer * <p/> * Bounded buffer using \Semaphore * * @author Brian Goetz and Tim Peierls */@ThreadSafepublic class SemaphoreBoundedBuffer <E&...原创 2018-06-16 21:04:54 · 278 阅读 · 0 评论 -
在synchronized和ReentrantLock之间进行选择
在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。与ReentrantLock相比,内置锁的一个优点是:在线程转储中能给出在哪些调用帧中获得了哪些锁,并能够检测...原创 2018-06-17 16:33:56 · 586 阅读 · 0 评论 -
在基于散列的Map中使用锁分段技术
1、降低锁竞争的程度:减少锁的持有时间,降低锁的请求频率,使用带有协调机制的独占锁。缩小加锁代码的范围;缩小锁的粒度,对相互对立的共享变量使用不同的锁;对单个锁分解为两个锁,到分解为多个锁的锁分段,使同一时刻可以让更多线程同时操作不同分段锁锁定的分段。2、基于散列的Map实现,其中使用了锁分段技术。它拥有N_LOCKS个锁,并且每个锁保护散列桶的一个子集。大多数方法,列入get,都只需要获得一个锁...原创 2018-06-15 09:05:04 · 294 阅读 · 0 评论 -
模拟jdk1.6中AQS实现缩减版的FutureTask的get()方法
import java.util.concurrent.*;import java.util.concurrent.locks.AbstractQueuedSynchronizer;/** * @author Administrator * @date 2018/5/19 9:18 */public class FutureTask<V> implements Runna...原创 2018-05-19 21:29:34 · 423 阅读 · 0 评论 -
深入分析synchronized的实现原理
本文转载自公众号: Java技术驿站记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized。对于当时的我们来说,synchronized是如此的神奇且强大。我们赋予它一个名字“同步”,也成为我们解决多线程情况的良药,百试不爽。但是,随着学习的深入,我们知道synchronized是一个重量级锁,相对于Lock,它会显得那么笨重,以至于我们认为它不是那么的高效,并慢慢抛弃它。 ...转载 2018-06-01 09:10:49 · 176 阅读 · 0 评论 -
深入分析volatile的实现原理
本文转载自公众号: Java技术驿站通过前面一章,我们了解到synchronized是一个重量级的锁,虽然JVM对它做了很多优化。而下面介绍的volatile则是轻量级的synchronized。如果一个变量使用volatile,则它比使用synchronized的成本更加低,因为它不会引起线程上下文的切换和调度。Java语言规范对volatile的定义如下:Java编程语言允许线程访问共享变量,...转载 2018-06-01 09:20:25 · 218 阅读 · 0 评论 -
并发技巧清单
概念和规则:1、可变状态是至关重要的。 所有的并发问题都可以归结为如何协调对并发状态的访问。可变状态越少,就越容易确保线程安全性。2、尽量将域声明为final类型,除非需要它们是可变的。3、不可变对象已订购是线程安全的。 不可变对象能极大地降低并发编程的复杂性。它们更为简单而且安全,可以任意共享而无需使用加锁或保护性复制等机制。4、封装有助于管理复杂性。 在编写线程安全的程序时,...原创 2018-06-09 16:58:04 · 141 阅读 · 0 评论 -
关于ReentrantLock中的锁获取与释放简图
原创 2018-05-23 22:49:35 · 181 阅读 · 0 评论 -
推荐使用ScheduledThreadPoolExecutor替代Timer
Timer存在的问题1、发生异常时整个timer线程任务都会取消。2、任务执行时间超出设置间隔时timer执行异常。3、系统时间调整或错误时影响timer执行建议使用ScheduledThreadPoolExecutor替代Timer主要方法说明:1、scheduleAtFixedRate,提交固定时间间隔的任务,前一个任务开始的时间和下一个任务开始的时间间隔2、scheduleWithFixed...原创 2018-05-23 23:09:39 · 470 阅读 · 0 评论 -
jdk 1.8 FutureTask
import java.util.concurrent.*;import java.util.concurrent.locks.LockSupport;/** * @author Administrator * @date 2018/5/26 12:23 */public class FutureTask<V> implements RunnableFuture<V...原创 2018-05-27 12:18:21 · 400 阅读 · 0 评论 -
Java 7 / 8 中的 HashMap 和 ConcurrentHashMap 全解析
转自:https://javadoop.com/post/hashmap今天发一篇"水文",可能很多读者都会表示不理解,不过我想把它作为并发序列文章中不可缺少的一块来介绍。本来以为花不了多少时间的,不过最终还是投入了挺多时间来完成这篇文章的。网上关于 HashMap 和 ConcurrentHashMap 的文章确实不少,不过缺斤少两的文章比较多,所以才想自己也写一篇,把细节说清楚说透,尤其像 J...转载 2018-06-01 08:57:39 · 137 阅读 · 0 评论 -
深入分析ThreadLocal
本文转载自公众号: Java技术驿站ThreadLoacal是什么?ThreadLocal是啥?以前面试别人时就喜欢问这个,有些伙伴喜欢把它和线程同步机制混为一谈,事实上ThreadLocal与线程同步无关。ThreadLocal虽然提供了一种解决多线程环境下成员变量的问题,但是它并不是解决多线程共享变量的问题。那么ThreadLocal到底是什么呢?API是这样介绍它的:This class p...转载 2018-06-01 09:12:58 · 118 阅读 · 0 评论 -
Java自定义线程池
1、使用Executors工具类下的线程池方式创建的不足之处是使用了无界队列,如果任务执行时间过长,且任务数多的情况,可能会造成OOM2、自定义线程池,示例如下:static int thread_count = Runtime.getRuntime().availableProcessors();static ThreadFactory threadFactory = new ThreadFa...原创 2018-06-08 10:09:13 · 1118 阅读 · 0 评论 -
使用闭锁CountDownLatch来实现并发下统计执行时长
1、程序如下:public class TestHarness { public long timeTasks(int nThreads, final Runnable task) throws InterruptedException { final CountDownLatch startGate = new CountDownLatch(1);...原创 2018-06-09 09:20:32 · 539 阅读 · 0 评论 -
FutureTask实现先执行任务,后获取结果
1、实现Callable接口来创建线程的方式,可以拿到线程执行结果,结果包含正常执行完成返回的结果,或者发生异常时抛出的异常信息。Callable与Runnable的主要差异就是Runnable的run方法没有返回值,且不抛出异常,Callable的call方法有返回值且可以抛出异常。2、Future接口中定义了get方法,用来获取线程执行结果的返回值;RunnableFuture接口继承了Fut...原创 2018-06-09 11:21:50 · 2094 阅读 · 0 评论 -
关于信号量Semaphore的acquire与release的说明
1、Semaphore信号量作为一种流控手段,可以对特定资源的允许同时访问的操作数量进行控制,例如池化技术(连接池)中的并发数,有界阻塞容器的容量等。2、Semaphore中包含初始化时固定个数的许可,在进行操作的时候,需要先acquire获取到许可,才可以继续执行任务,如果获取失败,则进入阻塞;处理完成之后需要release释放许可。3、acquire与release之间的关系:在实现中不包含真...原创 2018-06-09 11:40:21 · 20767 阅读 · 0 评论 -
CyclicBarrier栅栏
1、CyclicBarrier类似于闭锁CountDownLatch,能阻塞一组线程直到某个事件发生。闭锁是一次性对象,一旦进入终止状态,就不能被重置;栅栏到某个事件发生之后,栅栏打开,栅栏将被重置,可以下次使用。闭锁的条件时等事件发生,一般为外部条件,栅栏用于等待其他线程,条件为业务线程自己控制。2、栅栏在迭代算法中非常有用:通常将一个问题拆分成一系列相互独立的子问题。3、当线程到达栅栏位置时将...原创 2018-06-09 13:32:09 · 193 阅读 · 0 评论 -
使用ConcurrentHashMap中的putIfAbsent为计算结果建立高效、可伸缩的高速缓存
1、使用HashMap实现缓存代码如下:/** * Memoizer1 * * Initial cache attempt using HashMap and synchronization * * @author Brian Goetz and Tim Peierls */public class Memoizer1 <A, V> implements Computab...原创 2018-06-09 16:44:31 · 455 阅读 · 0 评论 -
支持响应线程池关闭操作的Web服务器
1、在while循环条件中判断线程池是否标记为关闭,进行响应关闭操作;在stop中调用shutdown方法进行关闭。代码如下:/** * LifecycleWebServer * <p/> * Web server with shutdown support * * @author Brian Goetz and Tim Peierls */public class Li...原创 2018-06-10 08:40:57 · 313 阅读 · 0 评论 -
使用beforeExecute、afterExecute和terminated扩展ThreadPoolExecutor
1、无论任务是从run中正常返回,还是抛出一个异常而返回,afterExecute都会被调用。如果任务在完成后带有一个Error,那么就不会盗用afterExecute。2、如果beforeExecute抛出一个RuntimeException,那么任务将不被执行,并且afterExecute也不会被调用。3、在线程完成关闭操作时调用terminated,也就是在所有任务都已经完成并且所有工作者线...原创 2018-06-11 08:45:09 · 6490 阅读 · 0 评论 -
死锁之锁顺序
1、由于不同线程对两个锁获取的顺序不一致造成的死锁,叫做锁顺序死锁。2、代码示例如下:/** * LeftRightDeadlock * * Simple lock-ordering deadlock * * @author Brian Goetz and Tim Peierls */public class LeftRightDeadlock { private final...原创 2018-06-11 22:44:06 · 1046 阅读 · 0 评论 -
死锁之动态锁顺序
1、由于方法入参由外部传递而来,方法内部虽然对两个参数按照固定顺序进行加锁,但是由于外部传递时顺序的不可控,而产生锁顺序造成的死锁,即动态锁顺序死锁。2、示例代码如下:// Warning: deadlock-prone!public static void transferMoney(Account fromAccount, A...原创 2018-06-11 23:12:28 · 791 阅读 · 0 评论 -
死锁之协作对象、锁粒度、开放调用
1、在两个协作对象之间,A对象中的a方法加锁,在a方法内部去调用B对象中加锁的b方法;B对象中的加锁方法c去调用A对象中的加锁方法d,协作对象之间产生死锁。加锁的粒度应该适当,合理缩小锁粒度,降低死锁的产生,只对共享变量进行必要的同步。有原子性要求的方法例外。2、示例代码:/** * CooperatingDeadlock * <p/> * Lock-ordering deadl...原创 2018-06-12 08:37:00 · 676 阅读 · 1 评论