package cn.study.concurrency.ch14; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 使用condition作为挂起线程的信号 * 这个是先进先出的队列 * @author xiaof * * @param <T> */ public…
转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到空间可用:如果队列为空,那么take方法将阻塞直到有元素可用.队列可以是有界的也可以是无界的. 如果生产者生成工作的速率比消费者处理工作的速率款,那么工作项会在队列中累计起来,最终好紧内存.同样,put方法的阻塞特性也极大地简化了生产者的编码.如果使用有界队列,当队列充满时,生产者将阻…
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头结点和尾节点,他们分别指向队列的头和尾,尝试获取锁.入队列.释放锁等实现都与头尾节点相关,并且每个节点都引入前驱节点和后后续节点的引用:在等待机制上由原来的自旋改成阻塞唤醒.其结构如下: 知道其结构了,我们再看看他的实现.在线程获取锁时会调用AQS的acquire()方法,该方法第一次尝试获取锁如果失败,会将…
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么介绍的: 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier.…
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/读"."读/写"."写/写"操作都不能同时发生.然而在实际的场景中我们就会遇到这种情况:有些资源并发的访问中,它大部分时间都是执行读操作,写操作比较少,但是读操作并不影响数据的一致性,如果在进行读操作时采用独占的锁机制,这样势必会大大降低吞吐量.所以如果能够做…
注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的lock.unlock实现机制. ReentrantLock,可重入的互斥锁,是一种递归无阻塞的同步机制.它可以等同于synchronized的使用,但是ReentrantLock提供了比synchronized更强大.灵活的锁机制,可以减少死锁发生的概率. 对于ReentrantLock,官方有详细…
<Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 内存 磁盘 打印机 就跟下图所示: 一台简要的计算机 很久以前(也没多久,几十年前),计算机只能跑一个程序(可以回想下初学51时候的点灯程序).这个时候程序是非常的自由的,因为他可以占用整个计算机的所有的资源.如下所示: 点灯程序占用了所有的资源 往往有些程序很贱,明明占用着很多的资源,但是却不好好利用,上图…
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了头结点和尾节点,他们分别指向队列的头和尾,尝试获取锁.入队列.释放锁等实现都与头尾节点相关.而且每一个节点都引入前驱节点和后兴许节点的引用:在等待机制上由原来的自旋改成堵塞唤醒. 其结构例如以下: 知道其结构了,我们再看看他的实现.在线程获取锁时会调用AQS的acquire()方法.该方法第一次尝试获取锁假设…
摘要 在上一篇文章当中,讲到了CPU缓存导致可见性.线程切换导致了原子性.编译优化导致了有序性问题.那么这篇文章就先解决其中的可见性和有序性问题,引出了今天的主角:Java内存模型(面试并发的时候会经常考核到) 什么是Java内存模型? 现在知道了CPU缓存导致可见性.编译优化导致了有序性问题,那么最简单的方式就是直接禁用CPU缓存和编译优化.但是这样做我们的性能可就要爆炸了~.我们应该按需禁用. Java内存模型是有一个很复杂的规范,但是站在程序员的角度上可以理解为:Java内存模型规范了JV…
Java并发编程文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 前提 在第三篇文章最后的例子当中,需要获取到两个账户的锁后进行转账操作,这种情况有可能会发生死锁,我把上一章的代码片段放到下面: public class Account { // 余额 private Long money; public synchronized void transfer(Account t…
Java解决可见性和有序性问题:Java内存模型 什么是 Java 内存模型? Java 内存模型是个很复杂的规范,可以从不同的视角来解读,站在我们这些程序员的视角,本质上可以理解为, Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法.具体来说,这些方法包括 volatile.synchronized 和 final 三个关键字,以及六项 Happens-Before 规则. Happens-Before 规则:前一个操作的结果对后续操作可见. 前面一个操作的结果对后续操作…
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 lock方法,在调用acquireQueued(): if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; 在acquireQueued()中调用parkAndChec…
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInterruptibly(int arg): 以独占模式获取对象,如果被中断则中止. acquireShared(int arg): 以共享模式获取对象,忽略中断. acquireSharedInterruptibly(int arg)以共享模式获取对象,如果被中断则中止. tryAcquire(int…
上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一组线程互相等待,直到到达某个公共屏障点,才会进行后续任务".而CountDownlatch和它也有一点点相似之处:CountDownlatch所描述的是"在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待".在JDK API中是这样阐述的: 用给定的计数 初始化…
信号量Semaphore是一个控制访问多个共享资源的计数器,它本质上是一个"共享锁". Java并发提供了两种加锁模式:共享锁和独占锁.前面LZ介绍的ReentrantLock就是独占锁.对于独占锁而言,它每次只能有一个线程持有,而共享锁则不同,它允许多个线程并行持有锁,并发访问共享资源. 独占锁它所采用的是一种悲观的加锁策略,  对于写而言为了避免冲突独占是必须的,但是对于读就没有必要了,因为它不会影响数据的一致性.如果某个只读线程获取独占锁,则其他读线程都只能等待了,这种情况下就限…
前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获取锁.但是对于unlock()而已,它是不分为公平锁和非公平锁的. public void unlock() { sync.release(1); } public final boolean release(int arg) { if (tryRelease(arg)) { Node h = he…
学习Java并发已经有一个多月了,感觉有些东西学习一会儿了就会忘记,做了一些笔记但是不系统,对于Java并发这么大的"系统",需要自己好好总结.整理才能征服它.希望同仁们一起来学习Java并发编程,共同进步,互相指导. 在学习Java并发之前我们需要先理解一些基本的概念:共享.可变.线程安全性.线程同步.原子性.可见性.有序性. 共享和可变 要编写线程安全的代码,其核心在于对共享的和可变的状态进行访问. "共享"就意味着变量可以被多个线程同时访问.我们知道系统中的资…
废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor.线程池和Executor生命周期等内容,大部分是概念性的,请选择阅读. 切入正题 线程中执行任务 线程执行任务的两种策略:一是把所有的任务放在单个线程中串行执行,二是将每个任务放在各自的线程中执行.策略一的问题在于其糟糕的响应性和吞吐量:策略二的问题在于资源管理的复杂性. Executor框架 Ex…
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册.书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险.构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高并发应用程序的吞吐量,如何识别可并行执行的任务,如何提高单线程子…
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为:  Java并发性和多线程介绍目录 建议: <java并发编程实战>第3章和第4章可以暂时先跳过..这部分内容的文字和概念很多,代码块偏少.不容易看进去. 一.线程1.线程的使用可以提升程序的性能.2.线程如果没有同步,操作的执行顺序是不可预测的.3.线程之间共享数据时,必须使用同步机制.不然数据会发生无法预料的变化.二.线程的安全性 0.线程安全性:当多个线程访问某个对象时,…
<Java并发编程实战>和<Java并发编程的艺术>           Executor框架小结 1.在线程中如何执行任务 (1)任务执行目标: 在正常负载情况下,服务器应用程序要表现出良好的吞吐率和快速的响应性.在负载过载的情况下,应用程序的性能应该是逐渐减低的,而不是直接失败. 要实现高吞吐率和快速的响应,就应该选择清晰的任务边界和明确的任务执行策略. (2)任务执行策略有: 1)单线程串行执行任务:缺点:无法提高服务器应用程序的吞吐率和快速响应速度 2)根据任务显示创建线程…
更新时间:2017-06-03 <Java并发编程实战>文摘,有兴趣的朋友可以买本纸质书仔细研究下. 一 线程安全性 1.1 什么是线程安全性 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 在线程安全类中封装了必要的同步机制,因此客户端无须进一步采取同步措施. 示例:一个无状态的Servlet /** * @author Brian Goetz and Tim…
关于非阻塞算法CAS. 比较并交换CAS:CAS包含了3个操作数---需要读写的内存位置V,进行比较的值A和拟写入的新值B.当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不会执行任何操作.无论位置V的值是否等于A,都将返回V原有的值.然后线程可以基于新返回的V值来做对应的操作,可以反复尝试.通常,反复重试是一种合理的策略,但在一些竞争很激烈的情况下,更好的方式是在重试之前首先等待一段时间或者回退,从而避免造成活锁问题.CAS的主要缺点就是,它将使调用者处理竞争问题,而…
摘要 编写正确的并发程序对我来说是一件极其困难的事情,由于知识不足,只知道synchronized这个修饰符进行同步. 本文为学习极客时间:Java并发编程实战 01的总结,文章取图也是来自于该文章 并发Bug源头 在计算机系统中,程序的执行速度为:** CPU > 内存 > I/O设备 ** ,为了平衡这三者的速度差异,计算机体系机构.操作系统.编译程序都进行了优化: 1.CPU增加了缓存,以均衡和内存的速度差异 2.操作系统增加了进程.线程,已分时复用CPU,以均衡 CPU 与 I/O 设…
文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和有序性的问题,那么还有一个原子性问题咱们还没解决.在第一篇文章01并发编程的Bug源头当中,讲到了把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性,那么原子性的问题该如何解决. 同一时刻只有一个线程执行这个条件非常重要,我们称为互斥,如果能保护对共享变量的修改时互斥的,那么就能保住…
Java并发编程系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 Java并发编程实战 04死锁了怎么办 前提 在Java并发编程实战 04死锁了怎么办中,讲到了使用一次性申请所有资源来避免死锁的发生,但是代码中却是使用不断的循环去获取锁资源.如果获取锁资源耗时短.且并发冲突量不大的时候,这个方式还是挺合适的. 如果获取所以资源耗时长且并发冲突量很大的时候,可能会循环上千上万次,这…
未完待续. 阅读帮助 本文运用<如何阅读一本书>的学习方法进行学习. P15 表示对于书的第15页. Java并发编程实战简称为并发书或者该书之类的. 熟能生巧,不断地去理解,就像欣赏一部喜欢的电影,时不时就再看一遍,甚至把剧本下下来通读. 思想 1.虽然现在都是分布式系统,日新月异,但是代码层面的并发思想是可以学习借鉴的,在不同的层面上使用并发的设计理念. 2.本地上的并发安全加锁运行起来是比分布式redis锁快的,比较redis锁的交互需要通信,本地是代码层级的执行,还有就是用redis锁…
前面介绍了三个同步辅助类:CyclicBarrier.Barrier.Phaser,这篇博客介绍最后一个:Exchanger.JDK API是这样介绍的:可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象.Exchanger 可能被视为 SynchronousQueue 的双向形式.Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用. Exchanger,它允许在并发任务之间交…
在java中有两种方法实现锁机制,一种是在前一篇博客中([java7并发编程实战]-----线程同步机制:synchronized)介绍的synchronized,而另一种是比synchronized更加强大和领过的Lock.Lock确保当一个线程位于代码的临界区时,另一个线程不进入临界区,相对于synchronized,Lock接口及其实现类提供了更加强大.灵活的锁机制. 一个简单的锁 在使用synchronized时,我们是这样使用锁的: public class ThreadTest {…
在我们的实际应用当中可能经常会遇到这样一个场景:多个线程读或者.写相同的数据,访问相同的文件等等.对于这种情况如果我们不加以控制,是非常容易导致错误的.在java中,为了解决这个问题,引入临界区概念.所谓临界区是指一个访问共用资源的程序片段,而这些共用资源又无法同时被多个线程访问. 在java中为了实现临界区提供了同步机制.当一个线程试图访问一个临界区时,他将使用一种同步机制来查看是不是已经有其他线程进入临界区.如果没有则他就可以进入临界区,否则他就会被同步机制挂起,指定进入的线程离开这个临界区…