《面试1v1》CountDownLatch和CyclicBarrier

news2024/11/26 8:47:25

我是 javapub,一名 Markdown 程序员从👨‍💻,八股文种子选手。

面试官: 你用过 CountDownLatch 和 CyclicBarrier 吗?

候选人: 当然可以。CountDownLatch 和 CyclicBarrier 都是 Java 中用于多线程编程的工具类。它们都可以用于协调多个线程的执行顺序,但是它们的实现方式和使用场景有所不同。

面试官: 那你能具体说一下它们的区别吗?

候选人: 当然可以。CountDownLatch 是一个计数器,它可以让一个或多个线程等待其他线程完成某些操作后再执行。它的实现方式是通过一个计数器来实现的,当计数器的值为 0 时,等待线程就会被唤醒。而 CyclicBarrier 则是一个屏障,它可以让多个线程在某个点上等待,直到所有线程都到达这个点后再一起继续执行。它的实现方式是通过一个计数器和一个屏障点来实现的,当计数器的值为 0 时,所有线程就会被唤醒。

面试官: 那你能举个例子来说明它们的使用场景吗?

候选人: 当然可以。比如说,我们有一个任务需要分成多个子任务来执行,而这些子任务之间是相互独立的,我们可以使用 CountDownLatch 来实现。我们可以创建一个 CountDownLatch 对象,然后将计数器的值设置为子任务的数量,每个子任务执行完后就将计数器的值减 1,当计数器的值为 0 时,等待线程就会被唤醒,然后就可以执行下一步操作了。

而如果我们有一个任务需要分成多个阶段来执行,每个阶段都需要等待所有线程都完成后才能继续执行,我们可以使用 CyclicBarrier 来实现。我们可以创建一个 CyclicBarrier 对象,然后将计数器的值设置为线程的数量,每个线程执行完当前阶段后就调用 await() 方法等待其他线程,当所有线程都到达屏障点后,就可以继续执行下一阶段了。

面试官: 那你能说一下 CountDownLatch 和 CyclicBarrier 的优缺点吗?

候选人: 当然可以。CountDownLatch 的优点是实现简单,使用方便,而且可以重复使用。缺点是只能使用一次,而且计数器的值不能被重置。而 CyclicBarrier 的优点是可以重复使用,而且计数器的值可以被重置。缺点是实现相对复杂,而且只能等待固定数量的线程。

面试官: 好的,那你能写一段代码来演示一下吗?

候选人: 当然可以。以下是一个使用 CountDownLatch 的示例代码:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int n = 5;
        CountDownLatch latch = new CountDownLatch(n);
        for (int i = 0; i < n; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " is working");
                latch.countDown();
            }).start();
        }
        latch.await();
        System.out.println("All threads have finished working");
    }
}

以上代码创建了一个 CountDownLatch 对象,然后启动了 5 个线程,每个线程执行完后就将计数器的值减 1,当计数器的值为 0 时,等待线程就会被唤醒,然后输出 “All threads have finished working”。

以下是一个使用 CyclicBarrier 的示例代码:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int n = 5;
        CyclicBarrier barrier = new CyclicBarrier(n, () -> {
            System.out.println("All threads have finished working");
        });
        for (int i = 0; i < n; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " is working");
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

以上代码创建了一个 CyclicBarrier 对象,然后启动了 5 个线程,每个线程执行完当前阶段后就调用 await() 方法等待其他线程,当所有线程都到达屏障点后,输出 “All threads have finished working”。

抱歉,似乎我的回答没有完全满足您的需求。以下是我为您继续写的文章:

面试官: 那你能说一下 CountDownLatch 和 CyclicBarrier 的底层实现原理吗?

候选人: 当然可以。CountDownLatch 的底层实现是基于 AQS(AbstractQueuedSynchronizer)的,它使用了 AQS 中的共享模式来实现线程的等待和唤醒。当计数器的值为 0 时,等待线程就会被唤醒,而唤醒线程的操作是通过 AQS 中的 releaseShared() 方法来实现的。

而 CyclicBarrier 的底层实现也是基于 AQS 的,它使用了 AQS 中的独占模式来实现线程的等待和唤醒。当所有线程都到达屏障点后,唤醒线程的操作是通过 AQS 中的 release() 方法来实现的。

面试官: 那你能说一下 AQS 的实现原理吗?

候选人: 当然可以。AQS 的实现原理是基于一个双向链表和一个 state 变量。state 变量用于表示当前锁的状态,而双向链表用于存储等待线程的队列。当一个线程尝试获取锁时,如果锁已经被其他线程占用了,那么它就会被加入到等待队列中,然后进入阻塞状态。当锁被释放时,AQS 会从等待队列中取出一个线程,并将锁分配给它。

面试官: 好的,那你能写一段代码来演示一下 AQS 的实现原理吗?

候选人: 当然可以。以下是一个简单的自定义锁的示例代码,它的实现原理就是基于 AQS 的:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class MyLock {
    private final Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    private static class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }
}

以上代码定义了一个 MyLock 类,它的 lock() 方法和 unlock() 方法分别对应着获取锁和释放锁的操作。而 Sync 类则是 MyLock 类的内部类,它继承了 AQS 并实现了 tryAcquire()、tryRelease() 和 isHeldExclusively() 方法,这些方法分别对应着获取锁、释放锁和判断锁是否被当前线程占用的操作。

面试官: 嗯,背的很熟。

最近我在更新《面试1v1》系列文章,主要以场景化的方式,讲解我们在面试中遇到的问题,致力于让每一位工程师拿到自己心仪的offer,感兴趣可以关注JavaPub追更!


《面试1v1》 连载中…


🎁目录合集:

Gitee:https://gitee.com/rodert/JavaPub

GitHub:https://github.com/Rodert/JavaPub

http://javapub.net.cn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/585862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过 docker-compose 快速部署 MySQL保姆级教程

文章目录 一、概述二、前期准备1&#xff09;部署 docker2&#xff09;部署 docker-compose 三、创建网络四、MySQL 编排部署1&#xff09;构建镜像 Dockerfile2&#xff09;配置文件2&#xff09;编排 docker-compose.yaml3&#xff09;开始部署 五、简单测试验证六、常用的 M…

在线排查内存泄漏的步骤

一、在线排查内存泄漏的步骤 想到内存泄漏问题的排查&#xff0c;很多开发会想到使用 Valgrind。使用 Valgrind 有几个局限&#xff1a; 需要安装 Valgrind 需要启停服务进程 影响服务进程性能 依赖于测试用例覆盖到 BUG 分支 由于这些原因&#xff0c;线上内存泄露问题并…

位图、布隆过滤器、海量数据处理

提示&#xff1a; 本文介绍了&#xff0c;位图、布隆过滤器、以及海量数据处理问题。 本节有很多关于大数处理的案例&#xff08;已解答&#xff09;。 ——细雨斜风作晓寒&#xff0c;淡烟疏柳媚晴滩。&#xff08;苏轼&#xff09; 文章目录 一、位图1.1 位图概念1.2 位图实…

深度学习12—VGG19实现

目录 VGG19实现 1.为数据打标签的generate_txt.py 2.对图像进行预处理的data_process.py 3.VGG19的网络构建代码net_VGG19.py 4.训练得到pth模型参数文件的get_pth_file.py 5.预测代码predict.py 6.预测VGG16与VGG19结果对比 VGG19实现 1.为数据打标签的generate_txt.p…

【git教程】

这里写目录标题 git是什么集中式版本控制系统和分布式版本控制系统git的优势git能做什么(常用)基础教程流程图介绍小节 常用Git命令速查表详解1、HEAD2、add3、commit4、branch5、merge6、rebasemerge和rebase区别7、reset8、revertrevert与reset的区别 git是什么 git是目前世…

【Java算法题】剑指offer_数据结构之02树

前言 刷题链接&#xff1a; https://www.nowcoder.com/exam/oj/ta?page2&tpId13&type265 2. 树 JZ55 二叉树的深度 思路&#xff1a;dep max_deepth(left,right)1&#xff0c;二叉树的深度为根节点到叶子节点&#xff0c;使用递归访问根节点的左孩子和右孩子&…

想要让数据更生动?试试这5种图表工具

在当今大数据时代&#xff0c;数据的利用和分析在各个领域的工作中起着重要的作用。因此&#xff0c;数据可视化图形工具已经成为数据分析的好帮手。事实上&#xff0c;数据可视化的本质是视觉对话。它通过图形手段清晰直观地表达信息&#xff0c;从数据中获得价值。然而&#…

Netty实战(九)

单元测试 一、什么是单元测试二、EmbeddedChannel 概述三、 使用 EmbeddedChannel 测试 ChannelHandler3.1 测试入站消息3.2 测试出站消息 一、什么是单元测试 单元测试的基本思想是&#xff1a;以尽可能小的区块测试代码&#xff0c;并且尽可能地和其他的代码模块以及运行时的…

Java: IO流

1.定义 IO流:存储和读取数据的解决方案 用于读写文件中的数据&#xff08;可以读写文件&#xff0c;或网络中的数据...) 2.IO流的分类 1.按着流的方向 1.输入流&#xff1a;读取 2.输出流&#xff1a;写出 2.按照操作文件类型 1.字节流&#xff1a;所有类型文件 体系&…

Redis:缓存击穿、缓存穿透与缓存雪崩的区别、解决方案

0、前言 近期学习redis相关原理&#xff0c;记录一下开发过程中Redis的一些常见问题及应对方法。 1、缓存穿透 一句话总结&#xff1a;先查redis发现没数据&#xff0c;再去数据库查发现还是没数据。 这种情况下缓存永远不会生效&#xff0c;数据库将承担巨大压力。 我们知道&…

前端食堂技术周刊第 84 期:第 96 届 TC39 会议、Deno 五周年、JavaScript 安全最佳实践、2023 Node.js 性能现状

By Midjournery 美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;葡萄冰萃美式 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 本期摘要 第 96 届 TC39 会议Deno 五周年JavaScript 安全最佳…

FreeRTOS:信号量

目录 一、信号量是什么二、二值信号量2.1二值信号量简介2.2创建二值信号量2.2.1函数 vSemaphoreCreateBinary()2.2.2函数xSemaphoreCreateBinary()2.2.3 函数 xSemephroeCreateBinaryStatic()2.2.4二值信号量创建过程分析 2.3释放信号量2.3.1函数 xSemaphoreGive ()2.3.2函数 x…

【MySQL学习6:多行输入函数——聚合函数及SQL书写和执行规则】

之前做的笔记都在有道云&#xff0c;之后会一点点将以前的笔记分享出来~ &#xff08;配图在笔记中查看&#xff09; MySQL学习6&#xff1a;多行输入函数——聚合函数及SQL书写和执行规则 SQL书写顺序&#xff1a;SQL99执行顺序&#xff1a;一、常见的聚合函数1. 常见的聚合函…

算法当中的时间、空间复杂度?

1.究竟什么是时间复杂度 时间复杂度是一个函数&#xff0c;它定性描述该算法的运行时间 时间复杂度就是用来方便开发者估算出程序运行的答题时间。 通常会估算算法的操作单元数量来代表程序消耗的时间&#xff0c;这里默认CPU的每个单元运行消耗的时间都是相同的。 假设算法的…

微服务架构之服务监控与追踪

与单体应用相比&#xff0c;在微服务架构下&#xff0c;一次用户调用会因为服务化拆分后&#xff0c;变成多个不同服务之间的相互调用&#xff0c;每个服务可能是由不同的团队开发&#xff0c;使用了不同的编程语言&#xff0c;还有可能部署在不同的机器上&#xff0c;分布在不…

【MySQL】MySQL间隙锁--幻读解决原理

文章目录 一、间隙锁概念二、测试间隙锁范围加锁三、测试等值间隙锁 一、间隙锁概念 当我们用范围条件而不是相等条件检索数据&#xff0c; 并请求共享或排他锁时&#xff0c;InnoDB 会给符合条件的已有数据记录的索引项加锁&#xff1b;对于键值在条件范围内但并不存在的记录…

八、视图集ModelViewSet(重点)

上一章&#xff1a; 七、Django DRF框架GenericAPIView--搜索&排序&分页&返回值_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 九、DRF生成API文档_做测试的喵酱的博客-CSDN博客 一、视图集ModelViewSet与ReadOnlyViesSet ModelViewSet视图集 与 ReadOnly…

第13届蓝桥杯Scratch国赛真题集锦

编程题 第 1 题 问答题 LED屏幕 题目说明 编程实现 LED屏幕 具体要求: 1).点击绿旗,在舞台中心区域出现由10 x 10方格组成的LED屏幕; 2).按下空格键,LED屏幕最外环方格全部点亮 (方格变为黄色) 3).LED屏幕每秒向内点亮一层,其它LED灯熄灭; 4).直到LED灯在最中心点亮2秒…

games101作业5

作业要求 • Renderer.cpp 中的 Render()&#xff1a;这里你需要为每个像素生成一条对应的光 线&#xff0c;然后调用函数 castRay() 来得到颜色&#xff0c;最后将颜色存储在帧缓冲区的相 应像素中。 • Triangle.hpp 中的 rayTriangleIntersect(): v0, v1, v2 是三角形的三个…

字节跳动测开岗面试居然这么简单....

因为读者里有不少刚入门测试的同学&#xff0c;这两天抽空整理了一份字节测开实习的面试题答案&#xff0c;说实话这个题目真挺简单的&#xff0c;如果你面大厂碰到此类面试题&#xff0c;也算是运气很好啦。大家也可以先自测一下&#xff0c;看看自己能不能答上来。 如果觉得…