精华内容
下载资源
问答
  • Java并发编程精讲

    2021-06-16 03:15:48
    课程会讲解Java并发相关技术的基础、原理和应用,从线程安全、线程(池),锁实现和并发容器等高并发Java实现,去深入理解在并发编程中,一些最容易被忽视的点,这些点也是我在多年编程经验中实际用到,对于每个小节...
  • 主要介绍了java并发编程线程的基础知识,文中讲解非常详细,帮助大家更好的学习JAVA并发编程,感兴趣想学习JAVA的可以了解下
  • Java并发编程实践中的话:编写正确的程序并不容易,而编写...本场Chat作为Java并发编程之美系列的高级篇之二,主要讲解内容如下:(建议先阅读:Java编程之美:并发编程高级篇之一)rt.jar中Unsafe类主要函数讲解,Un
  • 本篇主要是建立一个对java并发基础知识的整个脉络结构,用来更好得理清并发的关系,不涉及各种工具类的使用和原理讲解等。

    目录

    什么是并发?

     如何使用线程?

    两种方法对比

    两种方法本质

    线程的生命周期

    线程的常用方法

    线程属性

    线程安全及性能问题

    什么是死锁

    什么是上下文切换?

    Java内存模型(JMM)


     

    本篇主要是建立一个对java并发基础知识的整个脉络结构,用来更好得理清并发的关系,不涉及各种工具类的使用和原理讲解等。

    上文是整个Java并发的思维导图,可能字有些小看不清楚,下面我逐个解释下

    什么是并发?

     

     如何使用线程?

    这里可能会有人不理解, 别的博客或书籍都有三种乃至四种。这里查看oracle官方文档,明确得知是两种。一种是继承Thread类,一种实现Runnable接口。

    https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Thread.html

    两种方法对比

    由于Java是单继承,如果继承Thread后就不能再继承其他类

    从耦合度方面来看,继承Thread类耦合度较高

    Thread都要创建类,对系统资源消耗比较大

    两种方法本质

    实现Runnable接口,实质是调用了target.run()方法

        /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see     #start()
         * @see     #stop()
         * @see     #Thread(ThreadGroup, Runnable, String)
         */
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }

    而继承Thread类实质是重写了run方法

    线程的生命周期

     

    线程的常用方法

     

    线程属性

    线程安全及性能问题

     

    什么是死锁

    线程安全方面肯定要说的是线程死锁问题。死锁简单说就是多个线程被阻塞,它们中的一个或多个在等待某个资源释放。如下图就是线程A持有资源2但是等待资源1,线程B持有资源1在等待资源2

     

    什么是上下文切换?

    即使是单核CPU也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程时同时执行的,时间片一般是几十毫秒(ms)。

    CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态,从任务保存到再加载的过程就是一次上下文切换

    这就像我们同时读两本书,当我们在读一本英文的技术书籍时,发现某个单词不认识, 于是便打开中英文词典,但是在放下英文书籍之前,大脑必须先记住这本书读到了多少页的第多少行,等查完单词之后,能够继续读这本书。这样的切换是会影响读 书效率的,同样上下文切换也会影响多线程的执行速度。

    Java内存模型(JMM)

    JMM因为涉及的篇幅内容较长,所以回头单开一篇讲JMM

    展开全文
  • Java并发知识

    2019-11-19 11:02:55
    java并发知识体系图 常用的并发工具类及原理: 线程池、synchronized、Lock 锁,悲观锁和乐观锁、可重入锁、公平锁和非公平锁、读写锁、ConcurrentHashMap、CopyOnWriteArrayList、ThreadLocal、6 种原子类、CAS ...

    java并发知识体系图

    在这里插入图片描述

    常用的并发工具类及原理:

    线程池、synchronized、Lock 锁,悲观锁和乐观锁、可重入锁、公平锁和非公平锁、读写锁、ConcurrentHashMap、CopyOnWriteArrayList、ThreadLocal、6 种原子类、CAS 原理、线程协作的 CountDownLatch、CyclicBarrier、Semaphore、AQS 框架、Java 内存模型、happens-before 原则、volatile 关键字、线程创建和停止的正确方法、线程的 6 种状态、如何解决死锁等

    Java实现线程的方法

    Java线程简单使用

    Java Thread和Runnable详解

    线程的状态详解

    Java Thread类API讲解

    展开全文
  • JAVA并发编程核心技术精讲

    千人学习 2018-04-28 06:09:39
    [JAVA工程师必会知识点之并发编程]       1、现在几乎100%的公司面试都必须面试并发编程,尤其是互联网公司,对于并发编程的要求更高,并发编程能力已经成为职场敲门砖。 2、现在已经是移动互联和...
  • 本文主要介绍Java并发 并发设计模型的知识,这里主要讲解 1. 什么是设计模式 2. 单例模式 3. 不变模式 4. Future模式 5. 生产者消费者,有需要的小伙伴可以参考下
  • Java并发编程简介

    2020-12-21 14:08:57
    并发编程简介 1. 什么是并发编程 所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在在同一实体上的多个事件。多个事件在同一时间间隔发生。 并发编程 ①从程序设计的角度来讲...它是Java语言中最为晦涩的

    并发编程简介

    1. 什么是并发编程
    所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在在同一实体上的多个事件。多个事件在同一时间间隔发生。
    并发编程
    ①从程序设计的角度来讲,是希望通过某些机制让计算机可以在一个时间段内,执行多个任务。
    ②从计算机CPU硬件层面来说,是一个或多个物理CPU在多个程序之间多路复用,提高对计算机资源的利用率。
    ③从调度算法角度来说,当任务数量多于CPU的核数时,并发编程能够通过系统的任务调度算法,实现多个任务一起执行。
    2.并发编程的重要性
    它是Java语言中最为晦涩的知识点,它涉及操作系统、内存、CPU、编程语言等多方面的基础能力,在开发语言中占据着无可替代的位置。
    3.并发编程的特性
    1.原子性
    2.可见性
    3.有序性
    4.并发编程的意义
    开发者通过使用不同的语言,实现并发编程,充分的利用处理器(CPU)的每一个核,以达到最高的处理性能,提升服务器的资源利用率,提升数据的处理速度。
    5.从CPU层面谈并发编程
    首先我们看下图,图中展示了最简单的CPU核心通过缓存与主存进行同通信的模型。
    在缓存出现后不久,系统变得越来越复杂,缓存与主存之间的速度差异被拉大,由于 CPU 的频率太快了,快到主存跟不上,这样在线程处理器时钟周期内,CPU 常常需要等待主存,这样就会浪费资源。从我们的感官上,计算机可以同时运行多个任务,但是从 CPU 硬件层面上来说,其实是 CPU 执行线程的切换,由于切换频率非常快,致使我们从感官上感觉计算机可以同时运行多个程序。为了避免长时间的线程等待,我们一方面提升硬件指标(如多级高速缓存的诞生,这里不做讨论),另一方面引入了并发概念,充分的利用处理器(CPU)的每一个核,减少 CPU 资源等待的时间,以达到最高的处理性能。
    6.操作系统,进程, 线程之间的联系与区别
    这三者之间的关系如图,操作系统是包含多个进程的容器,而每个进程又是容纳多个线程的容器。
    在这里插入图片描述
    什么是进程?
    官方定义:
    进程(baiProcess)是计算机中的程序关于某数据集合的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

    Tips:系统进行资源分配和调度的基本单位其实就是 CPU 时间片的切换,一个 CPU 同一时间只能操作一个任务,只不过 CPU 在不停的切换工作任务,这里的时间片就是我们所说的系统进行资源分配和调度的基本单位。
    

    那么从定义上感觉非常的抽象,但是进程其实就在我们日常的计算机使用过程中。请看下图,进入任务管理器看 Windows 操作系统下的进程:
    在这里插入图片描述
    什么是线程?
    官方定义:
    线程是操作系统能够进行资源调度的最小单位,它被包含在进行之中,是进程中的实际运作单位,单个线程执行的都是进程代码的某个片段,特定的线程总是在执行特定的任务。

    那么进程和线程有什么区别呢?

    - 诞生起源:现有进程,后有线程。进程由于资源利用率、公平性和便利性诞生。处理器的速度往往比外设的速度快(键盘、鼠标),为了提高 CPU 的利用率,诞生了线程,目的就是为了提高程序的执行效率。
    - 概念:进行是资源分配的最小单位。线程时程序执行的最小单位(线程是操作系统能够进行资源调度的最小单位,同个进程中的线程也可以被同时调度到多个 CPU 上运行),线程也被称作为轻量级进程。
    - 内存共享:默认情况下,进程的内存无法与其他进程共享(进程间通信通过 IPC 进行)。线程共享由操作系统分配给其父进程的内存块。
    7.串行,并行与并发
    串行:顺序执行,按部就班。在A任务执行完之前不能执行B。
    并行:同时执行,多管齐下。指两个或两个以上事件或活动在同一时刻发生。在多道程序环境下,并行性使多个程序同一时刻可在不同CPU核心上同时执行。
    并发:穿插执行,减少等待。指多个线程轮流穿插着执行,并发的实质是一个物理CPU在若干道程序之间多路复用,其目的是提高有限物理资源的运行效率。
    在这里插入图片描述
    小结
    本博客重点讲解了操作系统的并发原理,以及进程和线程之间的区别与联系。除此之外,理解串行,并行,并发三种线程执行方式的区别尤为重要,对以后的课程学习有很大的帮助。

    展开全文
  • Java并发编程实践(中文) 高清pdf 带书签。 详细讲解java并发知识,推荐
  • 前言 如果按照用途与特性进行粗略的划分,JUC 包中包含的工具大体可以分为 6 类: 执行者与线程池 并发队列 同步工具 并发集合 锁 原子变量 在【并发系列】中,主要讲解了 执行者与线程池,同步工具,锁 , 在分析...

    | 好看请赞,养成习惯

    • 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想

    • If you can NOT explain it simply, you do NOT understand it well enough

    现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star????


    前言

    如果按照用途与特性进行粗略的划分,JUC 包中包含的工具大体可以分为 6 类:

    1. 执行者与线程池

    2. 并发队列

    3. 同步工具

    4. 并发集合

    5. 原子变量

    在【并发系列】中,主要讲解了 执行者与线程池同步工具 , 在分析源码时,或多或少的提及到了「队列」,队列在 JUC 中也是多种多样存在,所以本文就以「远看」视角,帮助大家快速了解与区分这些看似「杂乱」的队列

    并发队列

    Java 并发队列按照实现方式来进行划分可以分为 2 种:

    1. 阻塞队列

    2. 非阻塞队列

    如果你已经看完并发系列锁的实现,你已经能够知道他们实现的区别:

    前者就是基于锁实现的,后者则是基于 CAS 非阻塞算法实现的

    常见的队列有下面这几种:

    瞬间懵逼?看到这个没有人性的图想直接走人?客观先别急,一会就柳暗花明了

    当下你也许有个问题:

    为什么会有这么多种队列的存在?

    锁有应对各种情形的锁,队列也自然有应对各种情形的队列了, 是不是也有点单一职责原则的意思呢?

    所以我们要了解这些队列到底是怎么设计的?以及用在了哪些地方?

    先来看下图

    如果你在 IDE 中打开以上非阻塞队列和阻塞队列,查看其实现方法,你就会发现,阻塞队列非阻塞队列 额外支持两种操作:

    1. 阻塞的插入

      当队列满时,队列会阻塞插入元素的线程,直到队列不满

    2. 阻塞的移除

      当队列为空时,获取元素的线程会阻塞,直到队列变为非空

    综合说明入队/出队操作,看似杂乱的方法,用一个表格就能概括了

    抛出异常

    • 当队列满时,此时如果再向队列中插入元素,会抛出 IllegalStateException (这很好理解)

    • 当队列空时,此时如果再从队列中获取元素,会抛出 NoSuchElementException  (这也很好理解)

    返回特殊值

    • 当向队列插入元素时,会返回元素是否插入成功,成功则返回 true

    • 当从队列移除元素时,如果没有则返回 null

    一直阻塞

    • 当队列满时,如果生产者线程向队列 put 元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出

    • 当队列为空时,如果消费者线程 从队列里面 take 元素,队列会阻塞消费者线程,直到队列不为空

    关于阻塞,我们其实早在 并发编程之等待通知机制 就已经充分说明过了,你还记得下面这张图吗?原理其实是一样一样滴

    超时退出

    和锁一样,因为有阻塞,为了灵活使用,就一定支持超时退出,阻塞时间达到超时时间,就会直接返回

    至于为啥插入和移除这么多种单词表示形式,我也不知道,为了方便记忆,只需要记住阻塞的方法形式即可:

    单词 puttake 字母 t 首位相连,一个放,一个拿

    到这里你应该对 Java 并发队列有了个初步的认识了,原来看似杂乱的方法貌似也有了规律。接下来就到了疯狂串知识点的时刻了,借助前序章节的知识,分分钟就理解全部队列了

    ArrayBlockingQueue

    之前也说过,JDK中的命名还是很讲究滴,一看这名字,底层就是数组实现了,是否有界,那就看在构造的时候是否需要指定 capacity 值了

    填鸭式的说明也容易忘,这些都是哪看到的呢?在所有队列的 Java docs 的第一段,一句话就概括了该队列的主要特性,所以强烈建议大家自己在看源码时,简单瞄一眼 docs 开头,心中就有多半个数了

    在讲 Java AQS队列同步器以及ReentrantLock的应用 时我们介绍了公平锁与非公平锁的概念,ArrayBlockingQueue 也有同样的概念,看它的构造方法,就有 ReentrantLock 来辅助实现

    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
    

    默认情况下,依旧是不保证线程公平访问队列(公平与否是指阻塞的线程能否按照阻塞的先后顺序访问队列,先阻塞线访问,后阻塞后访问)

    到这我也要临时问一个说过多次的面试送分题了:

    为什么默认采用非公平锁的方式?它较公平锁方式有什么好处,又可能带来哪些问题?

    知道了以上内容,结合上面表格中的方法,ArrayBlockingQueue 就可以轻松过关了

    和数组相对的自然是链表了

    LinkedBlockingQueue

    LinkedBlockingQueue 也算是一个有界阻塞队列 ,从下面的构造函数中你也可以看出,该队列的默认和最大长度为 Integer.MAX_VALUE ,这也就 docs 说 optionally-bounded 的原因了

    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
    
    public LinkedBlockingQueue(int capacity) {
      if (capacity <= 0) throw new IllegalArgumentException();
      this.capacity = capacity;
      last = head = new Node<E>(null);
    }
    

    正如 Java 集合一样,链表形式的队列,其存取效率要比数组形式的队列高。但是在一些并发程序中,数组形式的队列由于具有一定的可预测性,因此可以在某些场景中获得更高的效率

    看到 LinkedBlockingQueue 是不是也有些熟悉呢?为什么要使用线程池? 就已经和它多次照面了

    创建单个线程池

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    

    创建固定个数线程池

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    

    面试送分题又来了

    使用 Executors 创建线程池很简单,为什么大厂严格要求禁用这种创建方式呢?

    PriorityBlockingQueue

    PriorityBlockingQueue 是一个支持优先级的无界的阻塞队列,默认情况下采用自然顺序升序排列,当然也有非默认情况自定义优先级,需要排序,那自然要用到 Comparator 来定义排序规则了

    可以定义优先级,自然也就有相应的限制,以及使用的注意事项

    • 按照上图说明,队列中不允许存在 null 值,也不允许存在不能排序的元素

    • 对于排序值相同的元素,其序列是不保证的,但你可以继续自定义其他可以区分出来优先级的值,如果你有严格的优先级区分,建议有更完善的比较规则,就像 Java docs 这样

       class FIFOEntry<E extends Comparable<? super E>>
           implements Comparable<FIFOEntry<E>> {
         static final AtomicLong seq = new AtomicLong(0);
         final long seqNum;
         final E entry;
         public FIFOEntry(E entry) {
           seqNum = seq.getAndIncrement();
           this.entry = entry;
         }
         public E getEntry() { return entry; }
         public int compareTo(FIFOEntry<E> other) {
           int res = entry.compareTo(other.entry);
           if (res == 0 && other.entry != this.entry)
             res = (seqNum < other.seqNum ? -1 : 1);
           return res;
         }
       }
      
    • 队列容量是没有上限的,但是如果插入的元素超过负载,有可能会引起OutOfMemory异常(这是肯定的),这也是为什么我们通常所说,队列无界,心中有界

    • PriorityBlockingQueue 也有 put 方法,这是一个阻塞的方法,因为它是无界的,自然不会阻塞,所以就有了下面比较聪明的做法

      public void put(E e) {
          offer(e); // never need to block  请自行对照上面表格
      }
      
    • 可以给定初始容量,这个容量会按照一定的算法自动扩充

      // Default array capacity.
      private static final int DEFAULT_INITIAL_CAPACITY = 11;
      
      public PriorityBlockingQueue() {
          this(DEFAULT_INITIAL_CAPACITY, null);
      }
      

      这里默认的容量是 11,由于也是基于数组,那面试送分题又来了

      你通常是怎样定义容器/集合初始容量的?有哪些依据?

    DelayQueue

    DelayQueue 是一个支持延时获取元素的无界阻塞队列

    • 是否延时肯定是和某个时间(通常和当前时间) 进行比较

    • 比较过后还要进行排序,所以也是存在一定的优先级

    看到这也许觉得这有点和 PriorityBlockingQueue 很像,没错,DelayQueue 的内部也是使用 PriorityQueue

    上图绿色框线也告诉你,DelayQueue 队列的元素必须要实现 Depayed 接口:

    所以从上图可以看出使用 DelayQueue 非常简单,只需要两步:

    实现 getDelay() 方法,返回元素要延时多长时间

    public long getDelay(TimeUnit unit) {
       // 最好采用纳秒形式,这样更精确
        return unit.convert(time - now(), NANOSECONDS);
    }
    

    实现 compareTo() 方法,比较元素顺序

    public int compareTo(Delayed other) {
        if (other == this) // compare zero if same object
            return 0;
        if (other instanceof ScheduledFutureTask) {
            ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
            long diff = time - x.time;
            if (diff < 0)
                return -1;
            else if (diff > 0)
                return 1;
            else if (sequenceNumber < x.sequenceNumber)
                return -1;
            else
                return 1;
        }
        long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
        return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
    }
    

    上面的代码哪来的呢?如果你打开 ScheduledThreadPoolExecutor 里的 ScheduledFutureTask,你就看到了 (ScheduledThreadPoolExecutor 内部就是应用 DelayQueue)

    所以综合来说,下面两种情况非常适合使用 DelayQueue

    • 缓存系统的设计:用 DelayQueue 保存缓存元素的有效期,使用一个线程循环查询 DelayQueue,如果能从 DelayQueue 中获取元素,说明缓存有效期到了

    • 定时任务调度:用 DelayQueue 保存当天会执行的任务以及时间,如果能从 DelayQueue 中获取元素,任务就可以开始执行了。比如 TimerQueue 就是这样实现的

    SynchronousQueue

    这是一个不存储元素的阻塞队列,不存储元素还叫队列?

    没错,SynchronousQueue 直译过来叫同步队列,如果在队列里面呆久了应该就算是“异步”了吧

    所以使用它,每个put() 操作必须要等待一个 take() 操作,反之亦然,否则不能继续添加元素

    实际中怎么用呢?假如你需要两个线程之间同步共享变量,如果不用 SynchronousQueue 你可能会选择用 CountDownLatch 来完成,就像这样:

    ExecutorService executor = Executors.newFixedThreadPool(2);
    AtomicInteger sharedState = new AtomicInteger();
    CountDownLatch countDownLatch = new CountDownLatch(1);
    
    
    
    Runnable producer = () -> {
        Integer producedElement = ThreadLocalRandom
          .current()
          .nextInt();
        sharedState.set(producedElement);
        countDownLatch.countDown();
    };
    
    
    
    Runnable consumer = () -> {
        try {
            countDownLatch.await();
            Integer consumedElement = sharedState.get();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    };
    

    这点小事就用计数器来实现,显然很不合适,用 SynchronousQueue 改造一下,感觉瞬间就不一样了

    ExecutorService executor = Executors.newFixedThreadPool(2);
    SynchronousQueue<Integer> queue = new SynchronousQueue<>();
    
    Runnable producer = () -> {
        Integer producedElement = ThreadLocalRandom
          .current()
          .nextInt();
        try {
            queue.put(producedElement);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    };
    
    Runnable consumer = () -> {
        try {
            Integer consumedElement = queue.take();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    };
    

    其实 Executors.newCachedThreadPool() 方法里面使用的就是 SynchronousQueue

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    

    看到前面 LinkedBlockingQueue 用在 newSingleThreadExecutornewFixedThreadPool 上,而newCachedThreadPool 却用 SynchronousQueue,这是为什么呢?

    因为单线程池和固定线程池中,线程数量是有限的,因此提交的任务需要在LinkedBlockingQueue队列中等待空余的线程;

    而缓存线程池中,线程数量几乎无限(上限为Integer.MAX_VALUE),因此提交的任务只需要在SynchronousQueue 队列中同步移交给空余线程即可, 所以有时也会说 SynchronousQueue 的吞吐量要高于 LinkedBlockingQueueArrayBlockingQueue

    LinkedTransferQueue

    简单来说,TransferQueue提供了一个场所,生产者线程使用 transfer 方法传入一些对象并阻塞,直至这些对象被消费者线程全部取出。

    你有没有觉得,刚刚介绍的 SynchronousQueue 是否很像一个容量为 0 的 TransferQueue。

    但 LinkedTransferQueue 相比其他阻塞队列多了三个方法

    • transfer(E e)

      如果当前有消费者正在等待消费元素,transfer 方法就可以直接将生产者传入的元素立刻 transfer (传输) 给消费者;如果没有消费者等待消费元素,那么 transfer 方法会把元素放到队列的 tail(尾部)

      节点,一直阻塞,直到该元素被消费者消费才返回

    • tryTransfer(E e)

      tryTransfer,很显然是一种尝试,如果没有消费者等待消费元素,则马上返回 false ,程序不会阻塞

    • tryTransfer(E e, long timeout, TimeUnit unit)

      带有超时限制,尝试将生产者传入的元素 transfer 给消费者,如果超时时间到,还没有消费者消费元素,则返回 false

    你瞧,所有阻塞的方法都是一个套路:

    1. 阻塞方式

    2. 带有 try 的非阻塞方式

    3. 带有 try 和超时时间的非阻塞方式

    看到这你也许感觉 LinkedTransferQueue 没啥特点,其实它和其他阻塞队列的差别还挺大的:

    BlockingQueue 是如果队列满了,线程才会阻塞;但是 TransferQueue 是如果没有消费元素,则会阻塞 (transfer 方法)

    这也就应了 Doug Lea 说的那句话:

    LinkedTransferQueue is actually a superset of ConcurrentLinkedQueue,  SynchronousQueue (in “fair” mode), and unboundedLinkedBlockingQueues. And it’s made better by allowing you to mix and match those features as well as take advantage of higher-performance i mplementation techniques.

    简单翻译:

    LinkedTransferQueueConcurrentLinkedQueue, SynchronousQueue (在公平模式下), 无界的LinkedBlockingQueues等的超集; 允许你混合使用阻塞队列的多种特性

    所以,在合适的场景中,请尽量使用LinkedTransferQueue

    上面都看的是单向队列 FIFO,接下来我们看看双向队列

    LinkedBlockingDeque

    LinkedBlockingDeque 是一个由链表结构组成的双向阻塞队列,凡是后缀为 Deque 的都是双向队列意思,后缀的发音为deck——/dek/,  刚接触它时我以为是这个冰激凌的发音

    所谓双向队列值得就是可以从队列的两端插入和移除元素。所以:

    双向队列因为多了一个操作队列的入口,在多线程同时入队是,也就会减少一半的竞争

    队列有头,有尾,因此它又比其他阻塞队列多了几个特殊的方法

    • addFirst

    • addLast

    • xxxxFirst

    • xxxxLast

    • ... ...

    这么一看,双向阻塞队列确实很高效,

    那双向阻塞队列应用在什么地方了呢?

    不知道你是否听过 “工作窃取”模式,看似不太厚道的一种方法,实则是高效利用线程的好办法。下一篇文章,我们就来看看 ForkJoinPool 是如何应用  “工作窃取”模式的

    总结

    到这关于 Java 队列(其实主要介绍了阻塞队列)就快速的区分完了,将看似杂乱的方法做了分类整理,方便快速理解其用途,同时也说明了这些队列的实际用途。相信你带着更高的视角来阅读源码会更加轻松,最后也希望大家认真看两个队列的源码实现,在遇到队列的问题,脑海中的画面分分钟就可以搞定了

    参考

    1. Java 并发编程的艺术

    2. Java 并发编程之美

    3. https://zhuanlan.zhihu.com/p/27148381

    <<< 左右滑动见更多 >>>

    展开全文
  • 第1章 课程准备(入门课程) 6 节 | 42分钟课程目标:Java并发编程入门,适合没有并发编程经验的同学,本章首先从课程重点、特点、适合人群及学习收获几个方面对课程进行整体的介绍,然后会从一个实际的计数场景实现...
  • Java并发编程面试必备的知识点!

    千次阅读 2019-03-05 22:46:30
    相信不用我说,大家也都知道掌握并发编程对于一个 Java 程序员的重要性。但相对于其他 Java 基础知识点来说,并发编程更加抽象,涉及到的知识点很多很零散,实际使用也更...
  • Java并发必知的底层CPU知识

    千次阅读 2020-01-10 21:58:39
    跟着作者的65节课彻底搞懂Java并发原理专栏,一步步彻底搞懂Java并发原理。 作者简介:笔名seaboat,擅长工程算法、人工智能算法、自然语言处理、架构、分布式、高并发、大数据和搜索引擎等方面的技术,大多数编程...
  • java并发知识概述

    2019-05-19 11:05:00
    因为本人就是干大数据的,有时候避免不了需要去分析大数据的源码,去优化,修改大数据的源码,感觉到如果有同学的java并发知识不过关的话,有可能连阅读源码的任务也完成不了,更不用谈去优化,修改源码了。...
  • Java 并发编程实战_2012

    2017-09-21 00:21:25
    【描述】Java 并发编程实战_2012,主J要讲解并发编程相关的知识点,Java中的多线程部分以及并发处理的相关内容。 【版权声明】该资源应用与共享和交流学习,不作它用。如有侵权,请联系删除 【资源说明】改版后不能...
  • 深入理解Java并发之synchronized实现原理

    万次阅读 多人点赞 2017-06-04 17:44:44
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ... 出自【zejian的博客】...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深...
  • Java并发编程详解.md

    2019-11-11 21:11:18
    有关java并发知识总结:三种线程创建方式 深入理解Thread构造函数 Thread API #### CAS缺陷 ##### 循环时间长开销大,自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。 ##### 只能保证一个共享变量...
  • Java学习 面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。觉得内容不错再 Star!)。 另外推荐一篇原创:终极推荐!可能是最适合你的Java学习路线 方法 网站 书籍推荐! Java 并发进阶常见面试题...
  • 借用 Java 并发编程实践中...并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步;而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真...
  • JAVA 并发编程实战

    2017-09-16 16:53:20
    Java并发编程实战,本书从线程的基础知识,包括线程安全性,对象共享以及对象组合灯,到结构化并发编程,都提供了很详细的讲解
  • 01 - Java并发编程与高并发解决方案笔记-基础篇

    千次阅读 多人点赞 2018-04-23 01:54:47
    01 - Java并发编程与高并发解决方案笔记-基础篇 基础篇很重要!很重要!很重要!!!一定要理解和认真思考。 01 - Java并发编程与高并发解决方案笔记-基础篇 1.课程准备 2.并发编程基础 2-0 CPU多级缓存 2-1...
  • Java并发编程艺术

    2018-08-13 10:10:54
    详细介绍了Java并发编程知识点,以及结合实例进行讲解
  • 本文主要介绍Java并发锁的优化和注意事项,这里整理了详细的资料,并讲解了 1. 锁优化的思路和方法 2. 虚拟机内的锁优化 3. 一个错误使用锁的案例 4. ThreadLocal及其源码分析等知识,有需要的小伙伴可以参考下
  • 背景最近想更深入了解下Java多线程相关的知识,对Java多线程有一个全面的认识,所以想找一本Java多线程相关的书籍来阅读,最后我选择了《Java并发编程实战》这本个人认为还算相当不错,至于为什么选择它,下面有介绍...
  • java并发案例详细讲解

    千次阅读 2017-10-12 10:42:17
    对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了。而并发问题是绝大部分的程序员头疼的问题, 但话又说回来了,既然逃避不掉,那我们就坦然面对吧~今天就让我们一起来...
  • JAVA并发专题讲解

    2019-02-01 04:50:24
    从事java开发的朋友们,一定对并发不陌生,可是很多人一接触到并发就头大甚至对并发有些畏惧之心,不用害怕只要我们抱着一颗对知识好奇的心去迎接未知的技术,相信你一定可以,接下来我给大家讲述一下并发那些事。...
  • Java - 并发知识点提纲

    2017-08-19 15:03:05
    并发编程需要学习的内容 1.Runnable 2.Thread 3.Executor 控制线程 4.Callable 希望线程有返回值 5.sleep 希望线程+休眠 6.优先级 setPriority() getPriority() 7.让步 yield() 8.守护线程(后台线程) setDaemon()

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,441
精华内容 13,376
关键字:

java并发知识讲解

java 订阅