免费网站建设域名,无锡网络营销平台,温州做企业网站,域名备案和icp备案区别【死磕 Java 并发】系列是 LZ 在 2017 年写的第一个死磕系列#xff0c;一直没有做一个合集#xff0c;这篇博客则是将整个系列做一个概览。 先来一个总览图#xff1a; 【高清图#xff0c;请关注“Java技术驿站”公众号#xff0c;回复#xff1a;脑图JUC】 【死磕Java…【死磕 Java 并发】系列是 LZ 在 2017 年写的第一个死磕系列一直没有做一个合集这篇博客则是将整个系列做一个概览。 先来一个总览图  【高清图请关注“Java技术驿站”公众号回复脑图JUC】  【死磕Java并发】—–深入分析synchronized 的实现原理  synchronized 可以保证方法或者代码块在运行时同一时刻只有一个方法可以进入到临界区同时它还可以保证共享变量的内存可见性。深入分析 synchronized 的内在实现机制锁优化、锁升级过程。  【死磕Java并发】—–深入分析volatile的实现原理  volatile 可以保证线程可见性且提供了一定的有序性但是无法保证原子性。在 JVM 底层 volatile 是采用“内存屏障”来实现的。这篇博文将带你分析 volatile 的本质  【死磕Java并发】—–Java内存模型之happens-before  happens-before 原则是判断数据是否存在竞争、线程是否安全的主要依据保证了多线程环境下的可见性。 定义如下 如果一个操作happens-before另一个操作那么第一个操作的执行结果将对第二个操作可见而且第一个操作的执行顺序排在第二个操作之前。两个操作之间存在happens-before关系并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致那么这种重排序并不非法。 【死磕Java并发】—–Java内存模型之重排序  在执行程序时为了提供性能处理器和编译器常常会对指令进行重排序但是不能随意重排序不是你想怎么排序就怎么排序它需要满足以下两个条件 在单线程环境下不能改变程序运行的结果存在数据依赖关系的不允许重排序as-if-serial 语义保证在单线程环境下重排序后的执行结果不会改变。  【死磕Java并发】—–Java内存模型之分析volatile  volatile的内存语义是 当写一个 volatile 变量时JMM 会把该线程对应的本地内存中的共享变量值立即刷新到主内存中。当读一个 volatile 变量时JMM 会把该线程对应的本地内存设置为无效直接从主内存中读取共享变量总是说 volatile 保证可见性happens-before 是 JMM 实现可见性的基础理论两者会碰撞怎样的火花这篇博文给你答案。  【死磕Java并发】—–Java内存模型之从JMM角度分析DCL  DCL即Double Check Lock双重检查锁定。是实现单例模式比较好的方式这篇博客告诉你 DCL 中为何要加 volatile 这个关键字。  【死磕Java并发】—–J.U.C之AQSAQS简介  AQSAbstractQueuedSynchronizer即队列同步器。它是构建锁或者其他同步组件的基础框架如ReentrantLock、ReentrantReadWriteLock、Semaphore等为 JUC 并发包中的核心基础组件。  【死磕Java并发】—–J.U.C之AQSCLH同步队列  前线程已经等待状态等信息构造成一个节点Node并将其加入到CLH同步队列同时会阻塞当前线程当同步状态释放时会把首节点唤醒公平锁使其再次尝试获取同步状态。  【死磕Java并发】—–J.U.C之AQS同步状态的获取与释放  AQS的设计模式采用的模板方法模式子类通过继承的方式实现它的抽象方法来管理同步状态对于子类而言它并没有太多的活要做AQS提供了大量的模板方法来实现同步主要是分为三类独占式获取和释放同步状态、共享式获取和释放同步状态、查询同步队列中的等待线程情况。  【死磕Java并发】—–J.U.C之AQS阻塞和唤醒线程  当需要阻塞或者唤醒一个线程的时候AQS 都是使用 LockSupport 这个工具类来完成。 LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。  【死磕Java并发】—–J.U.C之重入锁ReentrantLock  一个可重入的互斥锁定 Lock它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义但功能更强大。ReentrantLock 将由最近成功获得锁定并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。 这篇博客带你理解 重入锁ReentrantLock 内在本质。  【死磕Java并发】—–J.U.C之读写锁ReentrantReadWriteLock  读写锁维护着一对锁一个读锁和一个写锁。通过分离读锁和写锁使得并发性比一般的排他锁有了较大的提升在同一时间可以允许多个读线程同时访问但是在写线程访问时所有读线程和写线程都会被阻塞。 读写锁的主要特性 公平性支持公平性和非公平性。重入性支持重入。读写锁最多支持65535个递归写入锁和65535个递归读取锁。锁降级遵循获取写锁、获取读锁在释放写锁的次序写锁能够降级成为读锁 【死磕Java并发】—–J.U.C之Condition  在没有Lock之前我们使用synchronized来控制同步配合Object的wait()、notify()系列方法可以实现等待/通知模式。在Java SE5后Java提供了Lock接口相对于Synchronized而言Lock提供了条件Condition对线程的等待、唤醒操作更加详细和灵活  【死磕Java并发】—-深入分析CAS  CASCompare And Swap即比较并交换。Doug lea大神在同步组件中大量使用 CAS 技术鬼斧神工地实现了Java 多线程的并发操作。整个 AQS 同步组件、Atomic 原子类操作等等都是以 CAS 实现的。可以说CAS是整个JUC的基石。  【死磕Java并发】—–J.U.C之并发工具类CyclicBarrier  CyclicBarrier一个同步辅助类。它允许一组线程互相等待直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中这些线程必须不时地互相等待此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用所以称它为循环 的 barrier。  【死磕Java并发】—–J.U.C之并发工具类CountDownLatch  CountDownLatch 所描述的是”在完成一组正在其他线程中执行的操作之前它允许一个或多个线程一直等待“。 用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法所以在当前计数到达零之前await 方法会一直受阻塞。之后会释放所有等待的线程await 的所有后续调用都将立即返回。  【死磕Java并发】—–J.U.C之并发工具类Semaphore  Semaphore信号量是一个控制访问多个共享资源的计数器。从概念上讲信号量维护了一个许可集。如有必要在许可可用前会阻塞每一个 acquire()然后再获取该许可。每个 release() 添加一个许可从而可能释放一个正在阻塞的获取者。但是不使用实际的许可对象Semaphore 只对可用许可的号码进行计数并采取相应的行动。  【死磕Java并发】—–J.U.C之并发工具类Exchanger  可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法与伙伴线程进行匹配并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger 可能在应用程序比如遗传算法和管道设计中很有用。  【死磕Java并发】—–J.U.C之Java并发容器ConcurrentHashMap  ConcurrentHashMap 作为 Concurrent 一族其有着高效地并发操作。在1.8 版本以前ConcurrentHashMap 采用分段锁的概念使锁更加细化但是 1.8 已经改变了这种思路而是利用 CAS  Synchronized 来保证并发更新的安全当然底层采用数组链表红黑树的存储结构。这篇博客带你彻底理解 ConcurrentHashMap。  【死磕Java并发】—–J.U.C之ConcurrentHashMap红黑树转换分析  在 1.8 ConcurrentHashMap 的put操作中如果发现链表结构中的元素超过了TREEIFY_THRESHOLD默认为8则会把链表转换为红黑树已便于提高查询效率。那么具体的转换过程是怎么样的这篇博客给你答案。  【死磕Java并发】—–J.U.C之Java并发容器ConcurrentLinkedQueue  ConcurrentLinkedQueue是一个基于链接节点的无边界的线程安全队列它采用FIFO原则对元素进行排序。采用“wait-free”算法即CAS算法来实现的。 CoucurrentLinkedQueue规定了如下几个不变性 在入队的最后一个元素的next为null队列中所有未删除的节点的item都不能为null且都能从head节点遍历到对于要删除的节点不是直接将其设置为null而是先将其item域设置为null迭代器会跳过item为null的节点允许head和tail更新滞后。这是什么意思呢意思就说是head、tail不总是指向第一个元素和最后一个元素后面阐述。 【死磕Java并发】—–J.U.C之Java并发容器ConcurrentSkipListMap  我们在Java世界里看到了两种实现key-value的数据结构Hash、TreeMap这两种数据结构各自都有着优缺点。 Hash表插入、查找最快为O(1)如使用链表实现则可实现无锁数据有序化需要显式的排序操作。红黑树插入、查找为O(logn)但常数项较小无锁实现的复杂性很高一般需要加锁数据天然有序。这里介绍第三种实现 key-value 的数据结构SkipList。SkipList 有着不低于红黑树的效率但是其原理和实现的复杂度要比红黑树简单多了。 ConcurrentSkipListMap 其内部采用 SkipLis 数据结构实现。  【死磕Java并发】—–J.U.C之阻塞队列ArrayBlockingQueue  ArrayBlockingQueue一个由数组实现的有界阻塞队列。该队列采用FIFO的原则对元素进行排序添加的。 ArrayBlockingQueue 为有界且固定其大小在构造时由构造函数来决定确认之后就不能再改变了。ArrayBlockingQueue 支持对等待的生产者线程和使用者线程进行排序的可选公平策略但是在默认情况下不保证线程公平的访问在构造时可以选择公平策略fair  true。公平性通常会降低吞吐量但是减少了可变性和避免了“不平衡性”。  【死磕Java并发】—–J.U.C之阻塞队列PriorityBlockingQueue  PriorityBlockingQueue是一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序升序排序当然我们也可以通过构造函数来指定Comparator来对元素进行排序。需要注意的是PriorityBlockingQueue不能保证同优先级元素的顺序。  【死磕Java并发】—–J.U.C之阻塞队列DelayQueue  DelayQueue是一个支持延时获取元素的无界阻塞队列。里面的元素全部都是“可延期”的元素列头的元素是最先“到期”的元素如果队列里面没有元素到期是不能从列头获取元素的哪怕有元素也不行。也就是说只有在延迟期到时才能够从队列中取元素。 DelayQueue主要用于两个方面 缓存清掉缓存中超时的缓存数据任务超时处理 【死磕Java并发】—–J.U.C之阻塞队列SynchronousQueue  SynchronousQueue与其他BlockingQueue有着不同特性 SynchronousQueue没有容量。与其他BlockingQueue不同SynchronousQueue是一个不存储元素的BlockingQueue。每一个put操作必须要等待一个take操作否则不能继续添加元素反之亦然。因为没有容量所以对应 peek, contains, clear, isEmpty ... 等方法其实是无效的。例如clear是不执行任何操作的contains始终返回false,peek始终返回null。SynchronousQueue分为公平和非公平默认情况下采用非公平性访问策略当然也可以通过构造函数来设置为公平性访问策略为true即可。若使用 TransferQueue, 则队列中永远会存在一个 dummy node这点后面详细阐述。SynchronousQueue非常适合做交换工作生产者的线程和消费者的线程同步以传递某些信息、事件或者任务。  【死磕Java并发】—–J.U.C之阻塞队列LinkedTransferQueue  LinkedTransferQueue 是基于链表的 FIFO 无界阻塞队列它出现在 JDK7 中。Doug Lea 大神说 LinkedTransferQueue 是一个聪明的队列。它是 ConcurrentLinkedQueue、SynchronousQueue (公平模式下)、无界的LinkedBlockingQueues 等的超集。  【死磕Java并发】—–J.U.C之阻塞队列LinkedBlockingDeque  LinkedBlockingDeque 是一个由链表组成的双向阻塞队列双向队列就意味着可以从对头、对尾两端插入和移除元素同样意味着 LinkedBlockingDeque 支持 FIFO、FILO 两种操作方式。 LinkedBlockingDeque 是可选容量的在初始化时可以设置容量防止其过度膨胀如果不设置默认容量大小为 Integer.MAX_VALUE。  【死磕Java并发】—–深入分析ThreadLocal  ThreadLocal 提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物因为访问某个变量通过其get 或 set 方法的每个线程都有自己的局部变量它独立于变量的初始化副本。ThreadLocal实例通常是类中的 private static 字段它们希望将状态与某一个线程例如用户 ID 或事务 ID相关联。 所以ThreadLocal与线程同步机制不同线程同步机制是多个线程共享同一个变量而ThreadLocal是为每一个线程创建一个单独的变量副本故而每个线程都可以独立地改变自己所拥有的变量副本而不会影响其他线程所对应的副本。可以说ThreadLocal为多线程环境下变量问题提供了另外一种解决思路。  【死磕Java并发】—–J.U.C之线程池ThreadPoolExecutor  鼎鼎大名的线程池。不需要多说!!!!! 这篇博客深入分析 Java 中线程池的实现。  【死磕Java并发】—–J.U.C之线程池ScheduledThreadPoolExecutor  ScheduledThreadPoolExecutor 是实现线程的周期、延迟调度的。 ScheduledThreadPoolExecutor继承 ThreadPoolExecutor 且实现了 ScheduledExecutorService 接口它就相当于提供了“延迟”和“周期执行”功能的 ThreadPoolExecutor。在JDK API中是这样定义它的ThreadPoolExecutor它可另行安排在给定的延迟后运行命令或者定期执行命令。需要多个辅助线程时或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时此类要优于 Timer。 一旦启用已延迟的任务就执行它但是有关何时启用启用后何时执行则没有任何实时保证。按照提交的先进先出 (FIFO) 顺序来启用那些被安排在同一执行时间的任务。  欢迎关注chenssy微信公众账号   转载于:https://juejin.im/post/5b542d84e51d4519044a8107