天道酬勤,学无止境

阿里一面:CyclicBarrier和CountDownLatch的区别?

引言

前面一篇文章我们《Java高并发编程基础三大利器之CountDownLatch》它有一个缺点,就是它的计数器只能够使用一次,也就是说当计数器(state)减到为 0的时候,如果 再有线程调用去 await() 方法,该线程会直接通过,不会再起到等待其他线程执行结果起到同步的作用。为了解决这个问题CyclicBarrier就应运而生了。

什么是CyclicBarrier

CyclicBarrier是什么?把它拆开来翻译就是循环(Cycle)和屏障(Barrier
在这里插入图片描述
它的主要作用其实和CountDownLanch差不多,都是让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障会被打开,所有被屏障阻塞的线程才会继续执行,不过它是可以循环执行的,这是它与CountDownLanch最大的不同。CountDownLanch是只有当最后一个线程把计数器置为0的时候,其他阻塞的线程才会继续执行。学习CyclicBarrier之前建议先去看看这几篇文章:

  • 《Java高并发编程基础之AQS》
  • 《Java高并发编程基础三大利器之Semaphore》
  • 《Java高并发编程基础三大利器之CountDownLatch》

    如何使用

    我们首先先来看下关于使用CyclicBarrier的一个demo:比如游戏中有个关卡的时候,每次进入下一关的时候都需要进行加载一些地图、特效背景音乐什么的只有全部加载完了才能够进行游戏:

    /**demo 来源https://blog.csdn.net/lstcui/article/details/107389371
    * 公众号【java金融】
    */
    public class CyclicBarrierExample {
    static class PreTaskThread implements Runnable {
        private String task;
        private CyclicBarrier cyclicBarrier;
    
        public PreTaskThread(String task, CyclicBarrier cyclicBarrier) {
            this.task = task;
            this.cyclicBarrier = cyclicBarrier;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 4; i++) {
                Random random = new Random();
                try {
                    Thread.sleep(random.nextInt(1000));
                    System.out.println(String.format("关卡 %d 的任务 %s 完成", i, task));
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
                System.out.println("本关卡所有的前置任务完成,开始游戏... ...");
            });
            new Thread(new PreTaskThread("加载地图数据", cyclicBarrier)).start();
            new Thread(new PreTaskThread("加载人物模型", cyclicBarrier)).start();
            new Thread(new PreTaskThread("加载背景音乐", cyclicBarrier)).start();
        }
    }
    }

    输出结果如下:
    在这里插入图片描述
    我们可以看到每次游戏开始都会等当前关卡把游戏的人物模型,地图数据、背景音乐加载完成后才会开始进行游戏。并且还是可以循环控制的。

    源码分析

    结构组成

    /** The lock for guarding barrier entry */
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    private final int parties;
    /* The command to run when tripped */
    private final Runnable barrierCommand;
    /** The current generation */
    private Generation generation = new Generation();
  • lock:用于保护屏障入口的锁
  • trip :达到屏障并且不能放行的线程在trip条件变量上等待
  • parties :栅栏开启需要的到达线程总数
  • barrierCommand:最后一个线程到达屏障后执行的回调任务
  • generation:这是一个内部类,通过它实现CyclicBarrier重复利用,每当await达到最大次数的时候,就会重新new 一个,表示进入了下一个轮回。里面只有一个boolean型属性,用来表示当前轮回是否有线程中断。

    主要方法

    await方法

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    /**
     * Main barrier code, covering the various policies.
     */
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
         try {
               //获取barrier当前的 “代”也就是当前循环
             final Generation g = generation;
            if (g.broken)
                throw new BrokenBarrierException();
    
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }
            // 每来一个线程调用await方法都会进行减1
            int index = --count;
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    // new CyclicBarrier 传入 的barrierCommand, command.run()这个方法是同步的,如果耗时比较多的话,是否执行的时候需要考虑下是否异步来执行。
                    if (command != null)
                        command.run();
                    ranAction = true;
                    // 这个方法1. 唤醒所有阻塞的线程,2. 重置下count(count 每来一个线程都会进行减1)和generation,以便于下次循环。
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }
    
            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                     // 进入if条件,说明是不带超时的await
                    if (!timed)
                         // 当前线程会释放掉lock,然后进入到trip条件队列的尾部,然后挂起自己,等待被唤醒。
                        trip.await();
                    else if (nanos > 0L)
                         //说明当前线程调用await方法时 是指定了 超时时间的!
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                     //Node节点在 条件队列内 时 收到中断信号时 会抛出中断异常!
                    //g == generation 成立,说明当前代并没有变化。
                    //! g.broken 当前代如果没有被打破,那么当前线程就去打破,并且抛出异常..
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                    //执行到else有几种情况?
                    //1.代发生了变化,这个时候就不需要抛出中断异常了,因为 代已经更新了,这里唤醒后就走正常逻辑了..只不过设置下 中断标记。
                    //2.代没有发生变化,但是代被打破了,此时也不用返回中断异常,执行到下面的时候会抛出  brokenBarrier异常。也记录下中断标记位。
                        Thread.currentThread().interrupt();
                    }
                }
               //唤醒后,执行到这里,有几种情况?
              //1.正常情况,当前barrier开启了新的一代(trip.signalAll())
              //2.当前Generation被打破,此时也会唤醒所有在trip上挂起的线程
              //3.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
                if (g.broken)
                    throw new BrokenBarrierException();
               //唤醒后,执行到这里,有几种情况?
            //1.正常情况,当前barrier开启了新的一代(trip.signalAll())
            //2.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
                if (g != generation)
                    return index;
               //唤醒后,执行到这里,有几种情况?
            //.当前线程trip中等待超时,然后主动转移到 阻塞队列 然后获取到锁 唤醒。
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
             lock.unlock();
        }
    }

    小结

    到了这里我们是不是可以知道为啥CyclicBarrier可以进行循环计数?
    CyclicBarrier采用一个内部类Generation来维护当前循环,每一个await方法都会存储当前的generation,获取到相同generation对象的属于同一组,每当count的次数耗尽就会重新new一个Generation并且重新设置count的值为parties,表示进入下一次新的循环。
    从这个await方法我们是不是可以知道只要有一个线程被中断了,当代的 generationbroken 就会被设置为true,所以会导致其他的线程也会被抛出BrokenBarrierException。相当于一个失败其他也必须失败,感觉有“强一致性“的味道。

    总结

  • CountDownLanch是为计数器是设置一个值,当多次执行countdown后,计数器减为0的时候所有线程被唤醒,然后CountDownLanch失效,只能够使用一次。
  • CyclicBarrier是当count0时同样唤醒全部线程,同时会重新设置countparties,重新new一个generation来实现重复利用。

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。

巨人的肩膀摘苹果

https://javajr.cn/
http://www.360doc.com/content/20/0812/08/55930996_929792021.shtml
https://www.cnblogs.com/xxyyy/p/12958160.html

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 阿里一面:CyclicBarrier和CountDownLatch的区别?
    引言 前面一篇文章我们《Java高并发编程基础三大利器之CountDownLatch》它有一个缺点,就是它的计数器只能够使用一次,也就是说当计数器(state)减到为 0的时候,如果 再有线程调用去 await() 方法,该线程会直接通过,不会再起到等待其他线程执行结果起到同步的作用。为了解决这个问题CyclicBarrier就应运而生了。 什么是CyclicBarrier CyclicBarrier是什么?把它拆开来翻译就是循环(Cycle)和屏障(Barrier)它的主要作用其实和CountDownLanch差不多,都是让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障会被打开,所有被屏障阻塞的线程才会继续执行,不过它是可以循环执行的,这是它与CountDownLanch最大的不同。CountDownLanch是只有当最后一个线程把计数器置为0的时候,其他阻塞的线程才会继续执行。学习CyclicBarrier之前建议先去看看这几篇文章: 《Java高并发编程基础之AQS》 《Java高并发编程基础三大利器之Semaphore》 《Java高并发编程基础三大利器之CountDownLatch》 如何使用 我们首先先来看下关于使用CyclicBarrier的一个demo:比如游戏中有个关卡的时候,每次进入下一关的时候都需要进行加载一些地图
  • CountDownLatch和CyclicBarrier模拟同时并发请求
      有时候要测试一下某个功能的并发能力,又不要想借助于其他测试工具,索性就自己写简单的demo模拟一个并发请求就最方便了。如果熟悉jemter的测试某接口的并发能力其实更专业,此处只是自己折腾着玩。 CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段。其实查看源码它们都是在内部维护了一个计数器控制流程的 CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行;CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。   CountDownLatch和CyclicBarrier的区别 CountDownLatch的计数器,线程完成一个记录一个,计数器是递减 计数器,只能使用一次CyclicBarrier的计数器 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行,计数器是递增 计数器提供reset功能,可以多次使用   另外Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。   通常我们模拟并发请求,一般都是多开几个线程,发起请求就好了。但是方式,一般会存在启动的先后顺序了,算不得真正的同时并发!怎么样才能做到真正的同时并发呢
  • CountDownLatch和Cyclicbarrier概念、区别及原理
    CountDownLatch和Cyclicbarrier概念、区别及原理 1、概念   CountDownLatch:具有计数器的功能,等待其他线程执行完毕,主线程在继续执行,用于监听某些初始化操作,并且线程进行阻塞,等初始化执行完毕后,通知主线程继续工作执行。值得注意的是CountDownLatch计数的次数一定要与构造器传入的数字一致,比如构造器传入的是3,则countDown()一定要执行3次,否则线程将一直阻塞。CountDownLatch通常用来控制线程等待,它可以让线程等待倒计时结束,再开始执行。  CyclicBrrier:翻译过来就是循环栅栏的意思,其作用就是多线程的进行阻塞,等待某一个临界值条件满足后,同时执行!假设有一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发,只要有一个人没有准备好,大家都等待! 2、区别   CountDownLatch: 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。  CyclicBrrier: N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。 3、Java 8 下源码分析 3.1 CountDownLatch源码 coutDownLatch 底层实现了QAS,具体源码后面再分析。 3.2 CyclicBrrier源码来源:https://blog.51cto.com
  • java并发编程 -CountDownLatch和CyclicBarrier在内部实现和场景上的区别
    前言CountDownLatch和CyclicBarrier两个同为java并发编程的重要工具类,它们在诸多多线程并发或并行场景中得到了广泛的应用。但两者就其内部实现和使用场景而言是各有所侧重的。内部实现差异前者更多依赖经典的AQS机制和CAS机制来控制器内部状态的更迭和计数器本身的变化,而后者更多依靠可重入Lock等机制来控制其内部并发安全性和一致性。 public class { //Synchronization control For CountDownLatch. //Uses AQS state to represent count. private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count); } int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } protected boolean
  • 面试官:说说CountDownLatch,CyclicBarrier,Semaphore的原理?
    CountDownLatchCountDownLatch适用于在多线程的场景需要等待所有子线程全部执行完毕之后再做操作的场景。举个例子,早上部门开会,有人在上厕所,这时候需要等待所有人从厕所回来之后才能开始会议。public class CountDownLatchTest { private static int num = 3; private static CountDownLatch countDownLatch = new CountDownLatch(num); private static ExecutorService executorService = Executors.newFixedThreadPool(num); public static void main(String[] args) throws Exception{ executorService.submit(() -> { System.out.println("A在上厕所"); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); }finally { countDownLatch.countDown(); System.out.println("A上完了"); } })
  • Java多线程之CountDownLatch、CyclicBarrier和Semaphore
    转自:http://www.liubey.org/countdownlatch_vs_cyclicbarrier/概述CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。CyclicBarrier : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。Semaphore:可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。举例1:CountDownLatch使用场景举例:体育课时老师拿着秒表测试同学的800米成绩,那需求就是很简单了,老师在起跑处组织大家一起跑的瞬间按下秒表计时开始,然后再终点处等待最后一个学生通过终点后开始汇集学生成绩。API相关:1)await(),阻塞等待,直到计数器清零2)await(int timeout, TimeUnit unit),使线程阻塞,除非被中断或者超过等待的最大时间如果达到计数器清零,则await返回true,如果等待超过了最大的等待时间,则返回false3)countDown(),计数器减一,当计数器清零时,await的线程被唤醒,线程继续执行4)getCount (),获取当前计数器的大小import java.util.concurrent.CountDownLatch;import java
  • Java 并发工具CountDownLatch和CyclicBarrier 原理解析
    [TOC] Java 并发工具CountDownLatch和CyclicBarrier 原理解析 一,简介 CountDownLatch 允许一个或者多个线程等待其他线程完成操作。 CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程达到一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。 二,代码演示 CountDownLatchDemo public class CountDownLatchDemo { public static final CountDownLatch count = new CountDownLatch(10); private static int j = 0; public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { new Thread( ()-> { System.out.println("我是"+(++j)); count.countDown(); } ).start(); } count.await(); System.out.println("我是总数"+j+"!!!"); } } 运行结果: 我是1
  • 2021-03-27 学习笔记:Java常用并发包
    Java常用并发包 一、Fork/Join Java7提供了Fork/Join用于并行执行任务的框架, 可以把一个大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 如果一个应用能被分解成多个子任务,并且组合多个子任务的结果就能够获得最终的答案,那么这个应用就适合用 Fork/Join 模式来解决,对开发来说也不再需要处理各种并行相关事务,例如同步、通信、死锁等问题,需要做的就是拆分任务并组合每个子任务的中间结果。 1.工作窃取 JDK1.7引入的Fork/Join框架就是基于工作窃取算法,是指某个线程从其他队列里窃取任务来执行。工作窃取算法的优点是充分利用线程进行并行计算,并减少了线程间的竞争,其缺点是在某些情况下还是存在竞争,比如双端队列里只有一个任务时。并且消耗了更多的系统资源,比如创建多个线程和多个双端队列。 一般会使用双端队列,比如AB线程分别处理AB两个任务队列,当有一个线程执行完一个任务队列时,会去窃取另一个未完成的队列任务,而被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。 source: Fork/Join框架介绍 2.类关系和API RecursiveAction不需要返回值。RecursiveTask通过泛型参数设置计算的返回值类型。ForkJoinPool提供了一系列的submit方法
  • Join,CountDownLatch,CyclicBarrier,Semaphore和Exchanger
    CountDownLatch允许一个或者多个线程等待其他线程完成操作,之后再对结果做统一处理; 适用场景,分布式系统中对多个微服务的调用,并发执行并且必须等待全部执行完成才能继续执行后续操作; 其实在java中默认的实现是join()方法,join()方法主要的作用是当前线程必须等待直到join线程执行完成之后才能继续执行后续的操作, 其本质就是轮询判断join线程是否存活,如果存活则主线程继续等待,否则,通过调用this.notifyAll()方法来继续执行主线程。 实例代码如下:public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() { System.out.println("this is thread 1"); } }); Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() { System.out.println("Thread2 is finish"); } }); thread1.start(); thread2.start(); /*thread1.join
  • Java并发工具辅助类代码实例
    java中的并发工具类 一:等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作。 packag``.fuzhulei; import java.util.concurrent.*; ​ /** * 减法计数器,主要是countDown(计数器1) 和 await(阻塞)方法,只有当计数器减为0的时候,当前线程才可以往下继续执行。 * 主要用于允许一个或多个线程等待其他线程完成操作 * @author Huxudong * @createTime 2020-04-05 00:04:36 **/ public class CountDownDemo { public static void main(String[] args) throws InterruptedException { /** 使用其构造函数,创建一个数值为6的计数器 */ CountDownLatch countDownLatch = new CountDownLatch(6); /** 自定义线程池使用 */ ExecutorService pool = new ThreadPoolExecutor( 6, // 核心线程池大小 9, // 最大线程池的大小(根据是IO密集型,还是CPU密集型来确定大小) 3L, // 超时等待时间 TimeUnit
  • 如何等待多个线程完成?(How to wait for a number of threads to complete?)
    问题 有什么方法可以简单地等待所有线程处理完成? 例如,假设我有: public class DoSomethingInAThread implements Runnable{ public static void main(String[] args) { for (int n=0; n<1000; n++) { Thread t = new Thread(new DoSomethingInAThread()); t.start(); } // wait for all threads' run() methods to complete before continuing } public void run() { // do something here } } 如何更改此方法,以便main()方法在注释处暂停,直到所有线程的run()方法退出? 谢谢! 回答1 您将所有线程放入一个数组,全部启动,然后进行循环 for(i = 0; i < threads.length; i++) threads[i].join(); 每个连接将阻塞,直到相应的线程完成为止。 线程的完成顺序可能不同于您加入线程的顺序,但这不是问题:退出循环时,所有线程均已完成。 回答2 一种方法是制作一个Thread List ,创建并启动每个线程,同时将其添加到列表中。 一切启动后,循环遍历该列表
  • 爆赞!Android岗大厂面试官常问的那些问题,论程序员成长的正确姿势
    开头 昨天去面了一家公司,价值观有受到冲击。 面试官技术方面没的说,他可能是个完美主义的人,无论什么事情到了他那里好像都有解决的方案,我被说的无所适从,感觉他很厉害。 但我不能认可的是,面试官觉得加班是理所当然的,还说有人想把事情做的更好,愿意自主加班。这个我不否认,但凭什么说加班说的那么理所当然,违背国家制度也这么理所当然吗? 他问我对加班的看法。我说可以加班,有意义就可以。他继而反问,有些人觉得给老板打工就是没意义的,那是否所有加班都是没意义的呢?我当然说不是,他这么以己度人,我无语了。 我又说,忙的时候可以加,不会一直加下去吧?有没有阶段性休息和调整的说法? 他说没有,不到公司上市会一直保持这种状态。 顿时我不知道该说些啥,也许就是价值观的不同吧,似乎我不加班就说明我工作划水,效率低。 让你加班的,可能就是你的同行,这似乎有点儿悲哀。 阿里技术一面-35min 自我介绍 Android 有没有遇到OOM问题(有遇到内存泄漏问题)Handler机制ThreadLocalActivity启动到加载View过程View绘制过程LinearLayout (wrap_content) & TextView (match_parent) 最终结果???OKHttp(1. 为什么选择它? 2. 性能了解不?3. 内部有哪些设计模式)了解EventBus嘛? 设计模式
  • Java多线程中如何使用CountDownLatch?(How is CountDownLatch used in Java Multithreading?)
    问题 有人可以帮助我了解什么是Java CountDownLatch以及何时使用它吗? 对于这个程序的工作方式,我没有一个很清楚的想法。 据我了解,所有三个线程同时启动,每个线程将在3000ms之后调用CountDownLatch。 因此,递减计数将逐一递减。 锁存器变为零后,程序将打印“ Completed”。 也许我的理解方式不正确。 import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class Processor implements Runnable { private CountDownLatch latch; public Processor(CountDownLatch latch) { this.latch = latch; } public void run() { System.out.println("Started."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); } } // --------
  • 海量面经来袭!阿里钉钉、ICBU、CBU、蚂蚁、全在这里了,看完要个20K没什么问题!
    前言 阿里提前批面了很多部门,除了淘系一面其他都过了,最终点了国际化中台的内推,在焦急等hr面中,分享面经,希望能帮到大家,都能拿到满意的offer~ 3.3阿里CBU一面 项目30分钟(流程+项目难点+部署) JVM类加载过程 主要类加载器有什么 双亲委派模型的好处 双亲委派模型怎么打破 什么软件/应用打破了双亲委派模型 常用设计模式介绍(代理模式、包装模式、工厂模式、适配器模式、责任链模式…) 包装模式在JDK中哪里应用了、责任链模式在哪里应用 工厂模式在Spring源码中哪里有应用 多线程在项目中的应用 定义线程池的方法 Callable和Runnable的区别 FutureTask介绍 BeanFactory和ApplicationContext区别 Bean的生命周期 Java中实现Map接口的有什么 遍历HashMap的几种方法 Java8中JVM运行时数据结构变化是什么(元空间取代了方法区) 为什么用元空间取代方法区 业界大数据新技术,比如Hadoop了解吗? Java中的包装类有什么用(Integer Long Double),为什么需要包装类 TCP的粘包?粘包怎么解决?UDP会粘包吗? TCP面向什么传输,UDP面向什么传输? RPC了解吗? 线程的声明周期? 迪杰斯特拉最短路径算法? 选择排序是稳定的吗,时间复杂度? 快排稳定吗,时间复杂度,什么时候性能最差?
  • 阿里巴巴多线程面试题汇总
    什么是线程? 1、线程是操作系统能够进⾏运算调度的最⼩单位,它被包含在进程之中,是进程中的实际运作单位,可以使⽤多线程对 进⾏运算提速。 ⽐如,如果⼀个线程完成⼀个任务要100毫秒,那么⽤⼗个线程完成改任务只需10毫秒什么是线程安全和线程不安全? 1、线程安全 线程安全: 就是多线程访问时,采⽤了加锁机制,当⼀个线程访问该类的某个数据时,进⾏保护,其他线程不能进⾏ 访问,直到该线程读取完,其他线程才可使⽤。不会出现数据不⼀致或者数据污染。 Vector 是⽤同步⽅法来实现线程安全的, ⽽和它相似的ArrayList不是线程安全的。 2、线程不安全 线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据 线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量、静态变量只有读操作,⽽⽆写操作,⼀般来说,这个全局变量是线程安全的;若有多个 线程同时执⾏写操作,⼀般都需要考虑线程同步,否则的话就可能影响线程安全。什么是⾃旋锁? ⾃旋锁是SMP架构中的⼀种low-level的同步机制。 1、当线程A想要获取⼀把⾃旋锁⽽该锁⼜被其它线程锁持有时,线程A会在⼀个循环中⾃旋以检测锁是不是已经可⽤了。 2、⾃选锁需要注意: 由于⾃旋时不释放CPU,因⽽持有⾃旋锁的线程应该尽快释放⾃旋锁,否则等待该⾃旋锁的线程会⼀直在那⾥⾃ 旋,这就会浪费CPU时间。
  • java多线程 CountDownLatch源码分析
    目录 简介 内部类Sync 字段sync,构造函数,方法2个await,countDown,getCount,toString 简介 package java.util.concurrent; import java.util.concurrent.locks.AbstractQueuedSynchronizer; /** * 一种同步帮助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。 * * <p>用给定的count初始化倒计时锁存器。 * 由于调用了倒计时方法,await方法会阻塞到当前的计数为零为止,之后会释放等待线程,任何后续的await调用都会立即返回。 * 这是一个一次性现象——计数不能被重置。如果你需要一个重置计数的版本,可以考虑使用CyclicBarrier。 * * <p>倒数锁存器是一种通用的同步工具,可以用于许多目的。 * 初始化计数为1的CountDownLatch用作简单的on/off latch或gate: * 所有在gate调用await的线程,直到它被调用countDown的线程打开。 * 初始化为n的CountDownLatch可以用来让一个线程等待N个线程完成某个操作,或者某个操作已经完成N次。 * * <p>CountDownLatch的一个有用的属性是 * 它不要求调用countDown的线程在继续之前等待计数达到零
  • JavaSE学习总结(二十)多线程进阶之JUC并发(上)/虚假唤醒/JUC解决生产者消费者问题/精准通知唤醒/读写锁/线程八锁问题/集合线程安全化/JUC常用辅助类/阻塞队列/同步队列
    一、什么是JUC? JUC就是Java的并发包java.util.concurrent的简写,是关于并发编程的API。 与JUC相关的有三个包:java.util.concurrent、java.util.concurrent.atomic、java.util.concurrent.locks。 二、并发和并行的区别 并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。(同一时间段)(通俗地讲:CPU 一核 ,模拟出来多条线程,天下武功,唯快不破,快速交替) 并行:在操作系统中是指,一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。(同一时刻)(通俗地讲:CPU 多核 ,多个线程可以同时执行) 下边这张图可以更形象地表示并发(上图)和并行(下图)的区别: 并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机 案例演示 获取CPU核数 public class Test1 { public static void main(String[] args) { // 获取cpu的核数 System.out.println(Runtime.getRuntime().availableProcessors()); } } 三、虚假唤醒 假如生产者
  • 全套学习!年末阿里百度等大厂技术面试题汇总,附超全教程文档
    为什么越来越多的年轻人感觉工作没有动力、职业发展没有希望,迷茫和中年危机等现象普遍发生? 人常说,安居才能乐业。 前些年,房价虽然也不低,但刚工作的年轻人,努力奋斗,攒上几年钱,再借点,踮踮脚,还是能够到的。 而现在。这样的房价,年轻人,即使再踮脚,甚至拉长脖子,也只能望房兴叹。因此,人除了不能安居外,同时也失去了奋斗的目标。所以,在工作中,表现不积极,得过且过也就不足为奇了。 面试经验 自己大大小小投了也有20多家公司,不过经历简历筛选以及笔试淘汰,最终就经历了7家公司的面试。下面我就把自己面试中问到的问题贴出来供大家参考,一些具体项目相关的就不贴了。 阿里巴巴 阿里是3月初开始投的,是自己第一次面试大型的互联网公司,当时自己的准备也不够充分,表现不是很好,经历了三次技术面,最后挂了。 一面 自我介绍hashmap和hashtablejdbc三次握手http状态码HTTPS加密:对称,非对称,CA证书handler线程池的使用sychonized,volatilebinderactivity绘制流程事件响应流程activity周期,启动模式 二面 自我介绍对自己项目的介绍,架构图呈现对MVP和MVVM的理解。四大启动模式,以及场景对应Handler的机制介绍,为什么不能在子线程初始化问题设计模式中的单例介绍,使用场景(Okhttp的Seesion存储等等)
  • 最强整理!写给程序员的Flutter详细教程,大厂直通车!
    前言 当你开始开始去跳槽面试的时候,明明只是一份15K的工作,却问你会不会热修复,懂不懂性能优化,火箭造得让你猝及不防,结果就是凉凉;现如今市场,热修复、性能优化、NDK、APP开发、架构、源码等可以说是现在高级Android开发求职的必备技能。 早期的鸟儿有虫吃,现如今做开发的门槛越来越高。 但是,术业有专攻,总有一些技术牛逼的程序员可以吊打、碾压面试官! 本人经常隔段时间就偷偷投点简历,请假出去面试几次,目的不是想跳槽,主要是为了看看市场上的技术流行趋势,顺便检验一下自己的水平,当然,如果面到了心仪的公司或者大厂,那不是更好嘛,哈哈哈! 前段时间收到了字节跳动的面试,虽然有点小震惊,但还是用平常心对待了。结果一不小心,面试的时候就吊打了面试官。 前后一个半小时的面试过程全程没卡壳,项目和算法全部搞定,甚至聊到了面试官的盲点 应届坎坷求职路 一个广州非985/211普通本科生,计算机科学与技术专业。以前老是梦想能考一个厉害一点的学府,学习物理专业(因为初中和高中对物理比较有兴趣),无奈高考考得不尽人意。来到了计算机专业,才知道有C语言这玩意。 2013年大一,专业C语言成绩太差,被分配到B班学习。临近学校工作室(有真实项目锻炼)招新,那时候基础太差,又不愿意做一个loser。正巧同乡会有一位学长进了该工作室,我向他了解了该工作室的情况,得知有移动Android开发方向。那年
  • 关于线程相关的知识
    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对 运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成改任务只需10毫秒。Java在语言层面对多线程提供了卓越的支 持,它也是一个很好的卖点。 2) 线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。 进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整的过程,这个过程也是进程本身从产生,发展到最终消亡的过程。多进程操作系统能同时达运行多个进程(程序),由于 CPU 具备分时机制,所以每个进程都能循环获得自己的CPU 时间片。由于 CPU 执行速度非常快,使得所有程序好像是在同时运行一样。 3) 如何在Java中实现线程? 在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承 java.lang.Thread 类或者直接调用Runnable接口来重写run(