JUC (java.util.concurrent)
文章平均质量分 71
java.util.concurrent 是在并发编程中很常用的实用工具类。此包包括了几个小的、已标准化的可扩展框架,以及一些提供有用功能的类,没有这些类,这些功能会很难实现或实现起来冗长乏味。大部分得源码和并发都是基于8/14连个版本进行解读
诗水人间
要想走的更远,就需要思考更深层次的问题。冷静、智慧、深沉是我所向往的
展开
-
一道面试题关于 ReentrantLock中的 Condition接口的使用案例,以及LockSupport的方式处理
一道面试题如下:要求用三个线程完成如下操作,线程A打印5次A线程B打印10次B线程C打印15次线程A打印5次A线程B打印10次B…如此循环打印这道题考点在于控制3个线程依此按照顺序执行如果使用Condition接口来完成则代码大致可以这样解法一、主要使用Condition接口的 await、signal方法import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLo原创 2020-11-13 00:38:54 · 20538 阅读 · 0 评论 -
以ReentrantLock的非公平锁为例深入解读AbstractQueuedSynchronizer源码
以下面这段代码为例,我们分析以下ReentrantLock的工作原理,聊一聊,ReentrantLock到底做了哪些事情!public class ReentrantLockTest { static ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { new Thread(()->{ lock.lock();原创 2020-11-05 02:15:21 · 47703 阅读 · 2 评论 -
CompletableFuture中方法的各种(多任务并发场景)使用案例----详解
一、简单介绍CompletableFuture是java8新增的并发工具类,继承了FutureTask的同步任务的特点,同时新增了异步调用的特点(其中异步的方法名称都带有Async),换而言之同步获取方法的返回值的方式可以用CompletableFuture完成,与此同时,想要异步获取方法的返回值也可以使用CompletableFuture来完成。异步带Async,并且底层执行的线程由ForkJoinPool支持。于此同时还多了异常处理(执行任务的时候可能会发生异常,以前使用FutureTask的同步原创 2020-08-14 16:13:56 · 129249 阅读 · 3 评论 -
java.util.concurrent.Semaphore 类源码的深入解读
源码先贴上,后面是实际使用的时候代码的执行流程import java.util.Collection;import java.util.concurrent.TimeUnit;public class Semaphore implements java.io.Serializable { private static final long serialVersionUID = -3222578661600680210L; // 序列化版本号 private final Sync sy原创 2020-10-14 10:53:50 · 74411 阅读 · 0 评论 -
java.util.concurrent.CountDownLatch 类的源码和解读
源码注释public class CountDownLatch { private final Sync sync; // 同步器 /** * 同步控制计数器 */ private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L;原创 2020-10-15 00:55:05 · 69650 阅读 · 0 评论 -
是使用Thread.sleep(200) 还是使用 LockSupport.parkNanos(200*1000*1000l) ?
相信这个问题很少人会想过问这个问题,但是看到相关文章后定然是新奇。我相信有很多人都知道LockSupport 这个工具类,但绝大多数人学JUC都只是处于应用JUC。没有对底层原理思考。那么在我提出这个问题的时候,你能说出其中的一二吗?Thread.sleep 与 LockSupport.parkNanos 两者现象都能让线程暂停下来,但是底层的原理有所区别。在java类库中2个方法都标有相应的注释,注释中解释到: sleep 虽然让线程暂停了,但是不会释放资源,而LockSupport.park会释原创 2022-03-27 05:12:45 · 4474 阅读 · 0 评论 -
并发工具类 java.util.concurrent.Phaser 移相器 你是否熟练掌握了呢?
下面这张图,看完文章后再看,主要意图在于再次看到文章后能快速回忆state值的说明。原创 2021-09-26 11:54:42 · 679 阅读 · 1 评论 -
wait会释放锁?当然会释放锁,代码见真招!!!
我在网上看到很多人错误的理解,认为wait不会释放锁,然而它们并没有任何理由,仅凭自己的认知,然后很骄傲的和人讲,wait不会释放锁,你这是误人子弟。殊不知他自己才是误人子弟。我先讲一讲原理,然后用代码来证明它,让那些还认为wait不会释放锁的同志闭嘴。赶紧改错还来的及原理其实很好理解,从设计的角度很容易分析出wait是会释放锁的。线程在运行的时候占用了计算机的共享资源,因为当前线程在使用它,然而当前线程进行了休眠例如 wait() 很浅显的道理,当前线程已经停止了,那意味着这个资源空闲了下来。那原创 2021-02-18 00:17:22 · 8767 阅读 · 11 评论 -
深入解读ReentrantLock中的Condition接口的实现类ConditionObject
前不久在给网友讲JUC源码,我布置了一些作业让他们做,我看到了他们返回给我的作业中在谈到Condition接口的方式对线程对象阻塞和唤醒的理解有点偏差。我布置的作业内容是让他们回答,超类Object、Condition接口、LockSupport 三种方式对线程进行阻塞和唤醒,它们各自的优点、缺点、特点其中讲到Condition接口的特点: 有网友回答我说Condition的使用依赖于ReentrantLock,必须通过ReentrantLock.newCondition()方法获取到Cond原创 2021-01-06 02:39:54 · 782 阅读 · 0 评论 -
AtomicInteger越界的处理方式
使用updateAndGet方法进行更新值,传入的是一个IntUnaryOperator接口,使用lambda表达式完成功能即可。下面是一个简单的例子public class ThreadLocalDemo { public static void main(String[] args) { AtomicInteger atomicInteger = new AtomicInteger(Integer.MAX_VALUE); atomicInteger.upda原创 2020-12-03 22:21:28 · 25871 阅读 · 0 评论 -
使用ForkJoin解决0到1百亿的求和问题-----一次测试和调优记录,掌握ForkJoinPool的核心用法
ForkJoin框架是jdk7产生的一个新的并发框架,从其名字得知两个词fork()拆分、join()合并就是利用拆分合并的思想,将一个大任务先拆分好,直到不能拆分为止,然后完成任务,最终将结果合并。下面代码是计算0-1百亿的和的三种计算方式。结果是肯定超过了Long所能表示的值,但没关系,我们只是举个例子,结果的值不重要,只需要3个结果一致即可先看一遍然后看后面解说import java.util.concurrent.ForkJoinPool;import java.util.concurr原创 2020-11-26 02:23:50 · 27486 阅读 · 4 评论 -
ReentrantReadWriteLock源码注释
AbstractQueuedSynchronizer是JUC底层的架构,也是JUC的重点要掌握的内容如果对AQS的原理和源码还不清楚可以看下我之前写的文章:以ReentrantLock的非公平锁为例深入解读AbstractQueuedSynchronizer源码AbstractQueuedSynchronizer源码源码注释,版本jdk14,如果是jdk8,部分源码可能不同,笔者认为,像这种源码的学习,看高版本的有助于学习先进思想,当然jdk8的源码也可以看,建议选择一个版本看即可,先掌握原理,原创 2020-11-25 19:46:02 · 28334 阅读 · 0 评论 -
ReentrantReadWriteLock常见问题,源码级别的讲解
ReentrantReadWriteLock源码注释ReentrantReadWriteLock中利用state的前16位表示读锁、后16位表示写锁而下面图片源码如果出现w就代表写锁的个数,r是读锁的个数写锁加锁失败的情况读锁没有释放,加写锁则会失败下面的方法是尝试加写锁时会执行的方法,判断的方法如下public final void acquire(int arg) { if (!tryAcquire(arg)) { // 尝试加锁,失败则需要进入队列 acquir原创 2020-11-25 04:34:08 · 29089 阅读 · 0 评论 -
java.util.concurrent.locks.ReentrantReadWriteLock源码的解读和注释
ReentrantReadWriteLock源码注释总结:state表示了读锁和写锁的上锁次数,前16为用来表示读锁次数,后16为表示写锁次数读读不加锁写读、写写会导致加锁import java.util.Collection;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.u原创 2020-11-24 05:32:51 · 42149 阅读 · 0 评论 -
以读写锁ReentrantReadWriteLock的读锁为例追踪源码
读写锁适合使用在读多写少的场景,如果写多读少,反而没有可重入锁的效率高,一般而言,能够使用读写改造的情况下,使用读写锁效率会更高。下面是一个读写锁的读锁使用案例class ShareData { private Integer num = 0; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); /** * get方法 */ public Integer getNum原创 2020-11-24 05:01:31 · 31665 阅读 · 1 评论 -
java.util.concurrent.CyclicBarrier类的源码和总结
下面是我对CyclicBarrier 类的注释内容CyclicBarrier 类比较简单,前提需要掌握ReentrantLock原理如果感觉没看够在juc专栏中找,关于ReentrantLock我写了好几篇博客,有详细的说明。总结:内部实际上通过ReentrantLock控制线程以及通过ReentrantLock得到Condition接口,通过condition控制线程CyclicBarrier的使用则是通过new CyclicBarrier(10)表示可以拦截10个线程,然后在多线程中通过awai原创 2020-11-21 04:43:19 · 32170 阅读 · 0 评论 -
线程池ThreadPoolExecutor的七大参数
七个参数的构造方法如下public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnabl原创 2020-11-13 03:43:00 · 41486 阅读 · 1 评论 -
AbstractQueuedSynchronizer源码解读---完整版注释
完结AQS源码解读(完整版)package java.util.concurrent.locks;/** * jdk14 完结 */import jdk.internal.misc.Unsafe;import java.util.ArrayList;import java.util.Collection;import java.util.Date;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.原创 2020-11-12 22:29:54 · 41483 阅读 · 0 评论 -
AtomicMarkableReference源码
AtomicMarkableReference和 AtomicStampedReference源码几乎相同,唯一区别就在于一个是int型的时间戳,而这个类则是布尔型的标记值。两者区别在于AtomicStampedReference可以知道修改了多少次,而AtomicMarkableReference则只知道有没有被修改过import java.lang.invoke.MethodHandles;import java.lang.invoke.VarHandle;public class Atomi原创 2020-11-12 00:52:31 · 56170 阅读 · 0 评论 -
AtomicStampedReference的源码
在我们使用CAS操作的时候会有一个问题那就是CAS过程中,预期值可能被更新了多次,最终又更新会预期值,这样判断cas操作则是成功的因为本次cas操作符合条件。AtomicStampedReference总的来说就是解决一个线程将A改成C,也就是说当前值是A。但是会出现A被改成B后又改回A,那么A改成C还是成功的。有些时候是不允许这种情况。因此有了AtomicStampedReference类,它在CAS的基础上加了一个时间戳的概念,实际上就是在原先需要预期值和新值,两个参数,现在需要另外加两个参数也就是原创 2020-11-12 00:41:13 · 56071 阅读 · 0 评论 -
手写一个自旋锁
开始之前需要掌握CAS原理、类AtomicReference的使用CAS的全称可以是CompareAndSet或者CompareAndSwap总的来说就是再更新值得时候需要判断一些原先值是否是预期值,是则更新,不是则更新失败我们都知道jdk的java.util.concurrent.atomic包下提供了以下原子变量类,例如AtomicBoolean、AtomicInteger、AtomicLong等一系列基本类型的原子变量类,但是有些时候我们希望有一个自定义的来也使用CAS操做,例如自定义User类原创 2020-11-07 02:31:46 · 54508 阅读 · 0 评论 -
简化 java.util.concurrent.CopyOnWriteArraySet 源码并总结知识点
通过查看源码会发现CopyOnWriteArraySet 底层用的是CopyOnWriteArrayList因此我们需要借鉴CopyOnWriteArrayList的源码资料:简化 java.util.concurrent.CopyOnWriteArrayList 源码并总结知识点会发现CopyOnWriteArraySet会比CopyOnWriteArrayList代码量少一些,因为本质就是给CopyOnWriteArrayList套了一层壳。这里我们需要思考的问题是Set是一个元素不重复的集合原创 2020-11-07 00:37:55 · 56702 阅读 · 0 评论 -
简化 java.util.concurrent.CopyOnWriteArrayList 源码并总结知识点
由于CopyOnWriteArrayList比较重要,这里我没有像以前一样直接删除方法体内部,而是保留主要方法并添加了注释通过观看源码,CopyOnWriteArrayList 和 ArrayList有一些明显的特点没有resize扩容,而是通过牺牲空间来提高并发性能的特点(写时拷贝原理)CopyOnWriteArrayList在较新版本的jdk不是使用ReentrantLock加锁,而是使用Synchronized加锁(底层做了优化Synchronized的效率高于ReentrantLock故新版原创 2020-11-07 00:21:45 · 53416 阅读 · 0 评论 -
ReentrantLock和AbstractQueuedSynchronizer的整体结构
去掉定义的方法,AQS和可重入锁留下了哪些结构?AbstractQueuedSynchronizer简化后的大致结构public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { private static final long serialVersionUID = 7373984972572414691L; // 序列原创 2020-11-05 02:17:24 · 44704 阅读 · 0 评论 -
深入ReentrantLock源码与解读
学习忠告ReentrantLock的源码涉及到的类比较多,如果想真正掌握ReentrantLock的原理,建议独自去阅读源码,会有更好的效果。课前小菜我们都知道ReentrantLock简称(可重入锁),我们也知道ReentrantLock可以实现非公平锁和公平锁机制(转载的一篇公平锁和非公平机制)。默认(指无参构造得到的ReentrantLock实例)是非公平锁,通过有参构造器传入一个boolean值,如果传入true则是公平锁。源码见真章:在阅读ReentrantLock前,我们将Ree原创 2020-11-03 04:22:47 · 45193 阅读 · 1 评论 -
公平锁和非公平锁
看到一篇文章写的比较好,易懂。自认为不可能写的更好了,但为了弥补知识盲区,引用一下这篇关于公平锁和非公平锁的地址一张图读懂非公平锁与公平锁概括来说:公平锁的意思就是,当已有资源释放了锁,则下一个获得锁的线程是线程队列最前面的一个。非公平锁则不能保证,释放锁的时候刚好来了一个线程那么这个线程就会获得到锁,反而线程队列中等待的线程没有获得到锁,这种体现了非公平的机制故称作非公平锁。默认的ReentrantLock和ReadWriteLock都是非公平锁。ReentrantLock可以使用带参数的构造方法转载 2020-10-23 03:37:59 · 79133 阅读 · 0 评论 -
线程等待和唤醒的三种方式(Object、Condition、LockSupport)
Object中的wait()、notify()让线程等待和唤醒Object.wait()、Object.notify()方法必须再synchronized修饰的代码块中才能正常使用,否则会报异常(语法不会显示有错误)如下如果注释synchronized (obj)会报java.lang.IllegalMonitorStateException: current thread is not owner正常使用必须在synchronized中使用!public static void main(Stri原创 2020-10-23 03:29:02 · 65986 阅读 · 0 评论 -
自旋方式
面试题:用两个线程,一个输出字母,一个输出数字,交替输出1A2B3C4D5E.....26Z自旋方式:就是自己一直原地打转适用场景:代码比较短,短时间内效率特别高(执行在用户 态,不经过内核态。)特点:不经过操作系统public class Test02 { enum ReadytoRun {T1,T2}; static volatile Readyto...原创 2019-10-17 21:50:43 · 134398 阅读 · 0 评论 -
synchronized同步锁的各种情况(类锁和实例锁)
synchronized特点:在同一时刻内。只能有一个线程有锁 synchronized锁分Class锁(加了static修饰)和 Class实例锁(无static)两种 其中 Class锁 全局只有一把锁,锁实例变量 有多少个实例变量就有多少把锁 最为关键的是要搞懂synchronized修饰产生的锁在哪里。是锁this?(this可以有多个,因为实例变量不一定相同,thi...原创 2019-12-06 02:13:52 · 121578 阅读 · 0 评论 -
Callable和DeferredResult多线程工具类的使用,提高tomcat的并发量
Callable是jdk提供的多线程工具类来自 java.util.concurrent.Callable;Callable的使用方式比较简单,对于一般的多线程使用Callable接口就可以完成。DeferredResult是由spring提供的一个多线程工具类,使用比较复杂,但是能做的事情更多来自 org.springframework.web.context...原创 2020-04-27 16:26:32 · 143293 阅读 · 0 评论 -
ArrayList哪几种情况下会报java.util.ConcurrentModificationException吗?
ArrayList是一个很常用的集合类,底层是一个数组,只不过ArrayList封装了数组,实现了一些好用的方法例如add()方法,size()方法,get()方法等一系列的方法,并且实现了动态的扩容数组。new ArrayList();创建了一个空数组,那么它的容量起始为0,为什么面试过程中很多人都说ArrayList的初始容量为10呢?原因在于当你第一次调用add()方法添加元素的时候会进行一次扩容。这时候就会扩容到默认的初始容量10在ArrayList中定义了一个常量DEFAULT_CAPACIT原创 2020-08-03 19:11:58 · 112813 阅读 · 0 评论 -
创建线程的4种方式
方式一:继承Thread类重写run方法class MyThread extends Thread{ @Override public void run() { System.out.println("启动自定义线程"); super.run(); }}//启动线程new MyThread().start();方式二:实现Runnable接口lambda表达式new Thread(()->{ System.out.pri原创 2020-08-09 14:42:10 · 113671 阅读 · 0 评论 -
可重入锁和不可重入锁的区别
不可重入锁示例(同一个线程不可以重入上锁后的代码段)如下是一个不可重入锁的逻辑过程,会发现执行main方法控制台会打印执行doJob方法前,然后就会一直线程阻塞,不会打印执行doJob方法过程中,原因在于第一次上锁后,由于没有释放锁,因此执行第一次lock后isLocked = true,这个时候调用doJob()内部又一次调用了lock()由于上个线程将isLocked = true,导致再次进入的时候就进入死循环。导致线程无法执行System.out.println("执行doJob方法过程中");这原创 2020-10-22 21:40:16 · 83418 阅读 · 3 评论 -
线程LockSupport类的park和unpark方法使用
面试题:用两个线程,一个输出字母,一个输出数字,交替输出1A2B3C4D5E.....26ZLockSupport.park()让当前线程阻塞LockSupport.unpark(t2)解锁t2线程import java.util.concurrent.locks.LockSupport;public class Test { static Thread t1=null,t2=null; public static void main(String[] args) {原创 2019-10-17 21:08:16 · 116455 阅读 · 6 评论 -
简化 java.util.concurrent.locks.LockSupport 类的源码
关于LockSupport原理看源码注释。总的来说LockSupport提供外部使用的是静态方法park()、unpark(Thread thread)分别是让线程阻塞和唤醒线程的两个方法而底层则是调用C写好的库Unsafe类实现线程的调度。这个类在juc包下的很多类中都有用到。需要了解即可。概括的说我们用Unsafe通过jvm操作线程,而jvm则是通过操作系统操作线程。unpark、和park前后顺序(先阻塞,还是先唤醒)的一个坑,找到该文章的LockSupport案例import jdk原创 2020-10-14 22:11:35 · 58099 阅读 · 0 评论 -
CAS(compare and swap)算法、保证原子性
CAS是支持并发的第一个CPU提供原子的测试并设置操作,通常在单位上运行这项操作。操作数为V,A,B。CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配(V==A),那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返...原创 2020-01-12 15:44:32 · 145567 阅读 · 0 评论 -
JAVA内存模型:Java Memory Model(JMM)
JMM的三大特性可见性 原子性 有序性volatile保证了可见性, 但是 原子性 和 有序性 不能保证。synchronized保证了原子性、可见性和有序性原创 2019-12-13 02:30:21 · 135838 阅读 · 0 评论 -
2-原子变量CAS算法(Compare And Swap)
CAS算法介绍:CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于管理对共享数据的并发访问。 CAS 是一种无锁的非阻塞算法的实现。 CAS 包含了 3 个操作数: 需要读写的内存值 V 进行比较的值 A 拟写入的新值 B 当且仅当 V 的值等于 A 时,CAS 通过...原创 2019-12-13 01:25:18 · 163808 阅读 · 0 评论 -
1-volatile关键字 内存可见性
假设内存中有个变量a=1;需要进行运算得到a的新值。在这个过程中:是通过CPU运算进行操作的。计算的过程 是从内存中将变量a 复制一份然后计算后,将返回的值重新写入内存中的变量a。(CPU是进行运算的、而内存是用来存储的。这种特性导致运算过程必须是拷贝一份数据给cpu运算,然后将结果重新返回给内存)上面的过程相当于一个线程操作,当有多个线程进行运算时那么就会出现一些问题:由于每个线程...原创 2019-12-13 01:15:02 · 129893 阅读 · 0 评论