![](https://img-blog.csdnimg.cn/20201014180756916.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
Java并发编程之美
文章平均质量分 79
Java并发编程之美 读书笔记
逆流者blog
不登高山,不知天之高也;不临深溪,不知地之厚也。
展开
-
Java并发编程(二十一)独占锁 ReentrantLock 的原理
此文为读书笔记,欢迎评论,讨论问题,共同进步!简介ReentrantLock 是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而被放入该锁的 AQS 阻塞队列里面。类图:从类图可以看到,ReentrantLock 是使用 AOS 来实现的,并且根据参数来决定其内部是一个公平还是非公平锁,默认是非公平锁。// 默认非公平锁public ReentrantLock() { sync = new NonfairSync(); }// fair原创 2021-06-10 23:15:21 · 578 阅读 · 0 评论 -
Java并发编程(二十)抽象同步队列 AQS
AQS-锁的底层支持AbstractQueuedSynchronizer抽象同步队列简称AQS,它是实现同步器的基础组件,并发包中锁的底层就是使用 AQS实现的。另外,大多数开发者可能永远不会直接使用 AQS,但是知道其原理对于架构设计还是很有帮助的。下面看下AQS 的类图结构,如图6-1所示。...原创 2021-06-05 23:00:16 · 211 阅读 · 1 评论 -
Java并发编程(十九)Java 并发包中锁原理剖析 LockSupport 工具类
LockSupport 工具类JDK 中的rtjar包里面的LockSupport是个工具类,它的主要作用是挂起和唤醒线程,该工具类是创建锁和其他同步类的基础。LockSupport类与每个使用它的线程都会关联一个许可证,在默认情况下调用 LockSupport类的方法的线程是不持有许可证的。LockSupport是使用 Unsafe类实现的,下面介绍 LockSupport 中的几个主要函数。1.void park()方法如果调用 park方法的线程已经拿到了与LockSupport关联的许可证,原创 2021-02-10 16:37:19 · 275 阅读 · 0 评论 -
Java并发编程(十八)Java 并发包中并发List源码剖析
介绍并发包中的并发List只有CopyOnWriteArrayList。CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行的修改操作都是在底层的一个复制的数组(快照)上进行的,也就是使用了写时复制策略。类图结构如图:在 CopyOnWriteArrayList 的类图中,每个CopyOnWriteArrayList对象里面有一个 array数组对象用来存放具体元素,ReentrantLock独占锁对象用来保证同时只有一个线程对 array 进行修改。这里只要记得 Re原创 2021-02-02 16:22:31 · 1229 阅读 · 0 评论 -
Java并发编程(十七)Java并发包中原子操作类原理
JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS 实现的,相比使用锁实现原子性操作这在性能上有很大提高。原子性操作类的原理大致相同,下面描述下AtomicLong类的实现原理以及JDK8中新增的LongAdder和 LongAccumulator类的原理。AtomicLongAtomicLong是原子性递增或者递减类,其内部使用 Unsafe 来实现,我们看下面的代码。public class AtomicLongTest { /** 原子计数器 */ priva原创 2021-02-01 15:59:49 · 294 阅读 · 0 评论 -
Java并发编程(十六)ThreadLocalRandom
ThreadLocalRandom类是 JDK 7在JUC包下新增的随机数生成器,它弥补了Random类在多线程下的缺陷。Random 类在JDK 7之前以及现在,java.util.Random 都是使用比较广泛的随机数生成工具类,而且java.lang.Math 中的随机数生成也使用的是java.util.Random的实例。...原创 2021-01-28 17:56:20 · 1019 阅读 · 1 评论 -
Java并发编程(十五)锁
乐观锁与悲观锁乐观锁和悲观锁是在数据库中引入的名词,但是在并发包锁里面也引入了类似的思想。悲观锁指对数据被外界修改持保守态度,认为数据很容易就会被其他线程修改,所以在数据被处理前先对数据进行加锁,并在整个数据处理过程中,使数据处于锁定状态。悲观锁的实现往往依靠数据库提供的锁机制,即在数据库中,在对数据记录操作前给记录加排它锁。如果获取锁失败,则说明数据正在被其他线程修改,当前线程则等待或者抛出异常。如果获取锁成功,则对记录进行操作,然后提交事务后释放排它锁。下面我们看一个典型的例子,看它如何使用悲观锁原创 2021-01-27 23:03:56 · 242 阅读 · 0 评论 -
Java并发编程(十四)伪共享
什么是伪共享为了解决计算机系统中主内存与CPU 之间运行速度差问题,会在CPU与主内存之间添加一级或者多级高速缓冲存储器(Cache)。这个Cache一般是被集成到 CPU 内部的,所以也叫 CPU Cache.图 2-6 所示是两级 Cache 结构。Cache1C和r2Geche1图2-6在Cache 内部是按行存储的,其中每一行称为一个Cache行。Cache 行(如图2-7所示)是 Cache 与主内存进行数据交换的单位,Cache行的大小一般为2的幂次数字节。有报在图 2-7当原创 2021-01-25 15:44:30 · 557 阅读 · 1 评论 -
Java并发编程(十三)Java 中的原子性操作
此文为读书笔记,欢迎评论,谈论问题,共同进步!原子性操作,是指执行一系列操作时,这些操作要么全部执行,要么全部不执行,不存在只执行其中一部分的情况。在设计计数器时一般都先读取当前值,然后+1,再更新。这个过程是读—改一写的过程,如果不能保证这个过程是原子性的,那么就会出现线程安全问题。Java 中的 CAS操作CAS(Compare and Swap),其是 JDK提供的非阻塞原子性操作,它通过硬件保证了比较一更新操作的原子性。JDK里面的Unsafe类提供了一系列的 compareAndSwap*原创 2021-01-23 22:59:22 · 1756 阅读 · 3 评论 -
Java并发编程(十二)Java 中共享变量的内存可见性问题
此文为读书笔记,欢迎评论,谈论问题,共同进步!Java 的内存模型先看下多线程下处理共享变 Java 的内存模型:Java内存模型规定,将所有的变量都存放在主内存中,当线程使用变量时,会把主内存里面的变量复制到自己的工作空间(工作内存),线程读写变量时操作的是自己工作内存中的变量。Java内存模型是一个抽象的概念,那么在实际实现中线程的工作内存是什么呢?上图是一个双核 CPU 系统架构,每个核有自己的控制器和运算器,其中控制器包含一组寄存器和操作控制器,运算器执行算术逻辑运算。每个核都有自己原创 2021-01-22 11:45:36 · 564 阅读 · 0 评论 -
Java并发编程(十一)多线程并发编程
此文为读书笔记,欢迎评论,谈论问题,共同进步!什么是多线程并发编程先区分下并发和并行:并发是指同一个时间段内多个任务同时都在执行,并且都没有执行结束;并行是说在单位时间内多个任务同时在执行;并发任务强调在一个时间段内同时执行,而一个时间段由多个单位时间累积而成,所以说并发的多个任务在单位时间内不一定同时在执行。在单CPU的时代多个任务都是并发执行的,这是因为单个 CPU同时只能执行一个任务。在单 CPU时代多任务是共享一个CPU的,当一个任务占用 CPU运行时,其他任务就会被挂起,当占用C原创 2021-01-21 17:38:16 · 386 阅读 · 0 评论 -
Java并发编程(十)ThreadLocal
ThreadLocalThreadLocal是 JDK包提供的,它提供了线程本地变量,也就是说创建了一个 ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免了线程安全问题。创建一个ThreadLocal变量后,每个线程都会复制一个变量到自己的本地内存.ThreadLocal 使用示例public class ThreadLocalTest { static ThreadLocal<原创 2021-01-21 11:59:03 · 208 阅读 · 6 评论 -
Java并发编程(九)守护线程与用户线程
守护线程与用户线程Java中的线程分为两类,分别为daemon线程(守护线程)和 user 线程(用户线程)。在JVM启动时会调用 main函数,main 函数所在的线程就是一个用户线程,其实在JVM内部同时还启动了好多守护线程,比如垃圾回收线程。那么守护线程和用户线程有什么区别呢?区别之一是当最后一个非守护线程结束时,VM 会正常退出,而不管当前是否有守护线程,也就是说守护线程是否结束并不影响JVM的退出。言外之意,只要有一个用户线程还没结束,正常情况下 JVM 就不会退出。创建一个守护线程原创 2021-01-21 11:54:38 · 225 阅读 · 0 评论 -
Java并发编程(八)线程死锁
什么是线程死锁死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去.图中的两个线程各持有一个资源占有不释放, 又想去获取对方持有的资源, 造成两个线程一直等待对方释放, 造成了死锁.死锁的产生须具备四个条件互斥条件∶ 指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源。请求并持有条件∶ 指一个线程已经持有了至原创 2021-01-20 14:06:02 · 98 阅读 · 0 评论 -
Java并发编程(七)线程中断
加粗样式斜体样式删除线格式Gamma公式展示 Γ(n)=(n−1)!∀n∈N\Gamma(n) = (n-1)!\quad\foralln\in\mathbb NΓ(n)=(n−1)!∀n∈N 是通过 Euler integralΓ(z)=∫0∞tz−1e−tdt .\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.Γ(z)=∫0∞tz−1e−tdt.#mermaid-svg-75XPL5yhdwrxNyFt .label{font-family:'原创 2021-01-19 22:59:12 · 139 阅读 · 0 评论 -
Java并发编程(六)让出CPU执行权的 yield方法
Thread 静态 yield 方法当一个线程调用yield方法时,当前线程会让出CPU使用权,然后处于就绪状态,线程调度器会从线程就绪队列里面获取一个线程优先级最高的线程,当然也有可能会调度到刚刚让出CPU的那个线程来获取CPU执行权。public class YieldTest implements Runnable { YieldTest() { // 创建并启动线程 Thread thread = new Thread(this); th原创 2021-01-19 22:57:03 · 778 阅读 · 0 评论 -
Java并发编程(五)让线程睡眠的 sleep 方法
sleep 会暂时放弃cpu的执行权, 但不会释放锁public class SleepTest { /** 创建一个独占锁 */ private static final Lock lock = new ReentrantLock(); public static void main(String[] args) { Thread threadA = new Thread(new Runnable() { @Override原创 2021-01-19 22:55:01 · 4185 阅读 · 0 评论 -
Java并发编程(四)等待线程执行终止的join方法
public class JoinTest { public static void main(String[] args) throws InterruptedException { Thread threadOne = new Thread(new Runnable() { @Override public void run() { try { Thread原创 2021-01-19 22:50:47 · 325 阅读 · 0 评论 -
Java并发编程(三)线程通知和等待
public class WaitNotifyTest { /** * 资源A */ private static volatile Object resourceA = new Object(); /** * 资源B */ private static volatile Object resourceB = new Object(); public static void main(String[] args) throw原创 2021-01-19 18:04:01 · 223 阅读 · 4 评论 -
Java并发编程(二)创建线程
创建线程的三种方式继承Thread类并重写run方法实现Runnable接口的run方法使用FutureTask方式继承Thread类并重写run方法public class ThreadTest { public static class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread原创 2021-01-15 11:34:01 · 63 阅读 · 0 评论 -
Java并发编程(一)线程
线程是进程中的一个实体,线程本身是不会独立存在;进程是代码在数据集合上的一次运行活动, 是系统进行资源分配调度的基本单位,线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。操作系统在分配资源时是把资源分配给进程的,但CPU 资源是被分配到线程的,因为真正要占用 CPU运行的是线程,所以也说线程是CPU分配的基本单位。在 Java中,当我们启动 main 函数时其实就启动了一个JVM的进程,而main 函数所在的线程就是这个进程中的一个线程,也称主线程。...原创 2021-01-14 23:50:17 · 93 阅读 · 0 评论