【Java多线程手写代码】(三):快手面试官让我手写代码实现三个线程按序输出1 2 3 4 5, 6 7 8 9 10, 11 12 13 14 15...

阿里面试题:手写两个线程一个线程打印1,一个线程打印0,依次交替 阿里一面上来就让手写一个多线程模型,利用condition来实现1和0的交替执行,着实把我弄懵逼了,凭借着自己微弱的记忆,大致写出了如下: 基本思路是: 1、线程 操作 (方法) 资源类 2、判断 干活 通知 3、利用while判断来防止虚假唤醒机制 第一种方法利用Lock进行加锁解锁: public class ProducerAndConsumer { public static void main(String[] args) 阅读详情

我是少侠露飞。学习塑造人生,技术改变世界。

前言

这是少侠在前段时间的面试中,被快手面试官真实问到过的题目(是真的快手面试官,没有吸引眼球哦)。

问题描述很简单:利用三个线程,第一个线程打印1 2 3 4 5, 第二个线程打印 6 7 8 9 10, 第三个线程打印11 12 13 14 15,然后第一个线程再打印16 17 18 19 20,然后第二个线程接着打印21… 依此类推,直到打印到60。

通过wait/notifyAll机制

/**
 * @author Carson
 * @date 2020/11/12 21:50
 */
public class Main {
    // 数字初始值
    private static int num = 1;
    private static final int MAX = 60;
    // 执行线程的标记字段,1表示线程A执行,2表示线程B执行,3表示线程C执行
    // 通过volatile保证可见性
    private static volatile int flag = 1;

    public static void main(String[] args) {
        Object monitor = new Object();
        Thread pOne = new Thread(new PrintOne(monitor));
        Thread pTwo = new Thread(new PrintTwo(monitor));
        Thread pThr = new Thread(new PrintThr(monitor));

        pOne.setName("线程A");
        pTwo.setName("线程B");
        pThr.setName("线程C");

        pOne.start();
        pTwo.start();
        pThr.start();

    }

    static class PrintOne implements Runnable {
        final Object monitor;

        public PrintOne(Object monitor) {
            this.monitor = monitor;
        }

        @Override
        public void run() {
            while (num < MAX) {
                synchronized (monitor) {
                	// 通过一个无限循环验证当前是否该线程A执行,
                	// 若不是就调用wait方法释放锁
                    while (flag != 1) {
                        try {
                            monitor.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(Thread.currentThread().getName() + "-->");
                    for (int i = 0; i < 5; i++) {
                        System.out.print(num + " ");
                        num++;
                    }
                    // 此处打印只为换行
                    System.out.println();
                    // 将flag标记置为B,目的在于唤醒线程B
                    flag = 2;
                    // 唤醒其它线程
                    monitor.notifyAll();
                }
            }
        }
    }

    static class PrintTwo implements Runnable {
        final Object monitor;

        public PrintTwo(Object monitor) {
            this.monitor = monitor;
        }

        @Override
        public void run() {
            while (num < MAX) {
                synchronized (monitor) {
                    while (flag != 2) {
                        try {
                            monitor.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(Thread.currentThread().getName() + "-->");
                    for (int i = 0; i < 5; i++) {
                        System.out.print(num + " ");
                        num++;
                    }
                    System.out.println();
                    // 将flag标记置为C,目的在于唤醒线程C
                    flag = 3;
                    monitor.notifyAll();
                }
            }
        }
    }

    static class PrintThr implements Runnable {
        final Object monitor;

        public PrintThr(Object monitor) {
            this.monitor = monitor;
        }

        @Override
        public void run() {
            while (num < MAX) {
                synchronized (monitor) {
                    while (flag != 3) {
                        try {
                            monitor.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(Thread.currentThread().getName() + "-->");
                    for (int i = 0; i < 5; i++) {
                        System.out.print(num + " ");
                        num++;
                    }
                    System.out.println();
                    // 将flag标记置为A,目的在于唤醒线程A
                    flag = 1;
                    monitor.notifyAll();
                }
            }
        }
    }

}

通过ReentrantLock和Condition实现

这种方法的思路在于:通过一个共享的ReentrantLock控制三个线程的访问,我们都知道ReentrantLock是可重入锁。我们可以通过条件变量Condition实现线程A给线程B发送信号唤醒B,线程B给线程C发送信号唤醒C,这样依次循环执行打印。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // 定义锁
        ReentrantLock lock = new ReentrantLock();
        // 打印线程A的condition
        Condition conditionA = lock.newCondition();
        // 打印线程B的condition
        Condition conditionB = lock.newCondition();
        // 打印线程C的condition
        Condition conditionC = lock.newCondition();
        // 实例化A线程
        Thread printerA = new Thread(new ReentrantLockSyncPrinter(lock, conditionA, conditionB));
        // 实例化B线程
        Thread printerB = new Thread(new ReentrantLockSyncPrinter(lock, conditionB, conditionC));
        // 实例化C线程
        Thread printerC = new Thread(new ReentrantLockSyncPrinter(lock, conditionC, conditionA));

        printerA.setName("线程A");
        printerB.setName("线程B");
        printerC.setName("线程C");

        printerA.start();
        Thread.sleep(100);
        printerB.start();
        printerC.start();

    }

}

class ReentrantLockSyncPrinter implements Runnable {
    // 初始值
    private static int num = 1;
    private static final int MAX = 60;
    // 打印次数
    private static final int COUNT = 5;
    // 打印锁
    final ReentrantLock reentrantLock;
    // 本线程打印所需的condition
    final Condition currCondition;
    // 下一个线程打印所需要的condition
    final Condition nextCondition;

    public ReentrantLockSyncPrinter(ReentrantLock reentrantLock, Condition currCondition, Condition nextCondition) {
        this.reentrantLock = reentrantLock;
        this.currCondition = currCondition;
        this.nextCondition = nextCondition;
    }

    @Override
    public void run() {
        // 获取锁,进入临界区
        reentrantLock.lock();
        try {
            while (num < MAX) {
                System.out.print(Thread.currentThread().getName() + "-->");
                // 连续打印COUNT次
                for (int i = 0; i < COUNT; i++) {
                    //打印字符
                    System.out.print(num + " ");
                    num++;
                }
                System.out.println();
                // 使用nextCondition唤醒下一个线程
                // 因为只有一个线程在等待,所以signal或者signalAll都可以
                nextCondition.signal();
                try {
                    // 本线程让出锁并等待唤醒
                    currCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            // 释放锁
            reentrantLock.unlock();
        }
    }
}
Java N个线程轮流打印数字 这里实现两个线程轮流打印1-100数字,即线程一打印1,3,5,…,线程二打印2,4,6,…。 class PrintThread implements Runnable { private byte[] flag; int number; public PrintThread(int number, byte[] flag) { this.number = number; ... 阅读详情

相关推荐

VSCode CMake 安装与配置详解

概述 在windows上使用cmake编译C/C++程序时,首先需要CMake,安装gcc/g++编译环境,然后使用VSCode 以及配置下CMakelist.txt。 所需工具: VSCode (需要安装以下插件) C/C++ C++ Intellisense CMake CMake tools CMake Tools Helper CMake MinGW 安装CMake 下载链接:...

Markus 8万+

多线程面试题(二)---手写生产者消费者模式

1.手写实现生产者,消费者 生产者A将num更新成1,消费者将num更新成0,轮训执行10次。 public class LockDemo { public static void main (String[] args) { //实现生产者,消费者 // 判断等待,业务,通知 Data data = new Data(); new Thread(() -> { for (int i = 0; i < 10; i++) { tr

yzx3105的博客 321

【Aseprite】制作Unity2D瓦片地图素材(平台游戏)

本文章用于记录用Aseprite软件制作2D平台游戏的瓦片地图的方法。

凡心所向,素履以往 5546

【Java多线程手写代码】(一):启动两个线程交替顺序打印奇偶数

两个线程交替打印奇偶数的问题

少侠露飞的学习笔记 1755

优雅谈大模型:“System2”与“System 1”

研究人员探索了三种System 2方法——RaR、S2A 和 BSM,这些方法已经成功提炼到新的LLM,这个新的模型与System 1相比,产生了更好的结果,而且成本低于System 2。然而这种方法是有局限性,只能适用于特定的任务。

鲁班模锤 5154

Cadence Allegro实战:如何精准导入结构DXF文件避免安装偏差(附图层配置技巧)

本文详细讲解了在Cadence Allegro中精准导入结构DXF文件以避免安装偏差的实战技巧。核心在于导入前的单位校准、创建专用图层结构,以及基于坐标基准点的精确对齐方法。文章还分享了将DXF图形转化为正式板框和禁布区、高效管理图层以及向结构工程师导出DXF的完整流程,帮助PCB工程师确保设计与机械结构完美契合。

1a2s3d4f5g的博客 506

多线程并发场景题(持续更新)

多线程场景

lannister_awalys_pay的博客 495

GAMES101作业3-遇到的各种问题及解决方法

记录在做作业3时遇到的一些坑!以及最后的解决办法。

qq_41835314的博客 6817

Android基础面试常常吊死在这几个问题上,1个、2个、3个、4个、5个、6个、7个、8个、9个、10个......

我讲完你就回去等通知吧!BuildType定义了Gradle在构建和打包Android应用时使用的属性。一般这样可以用到,1、BuildType定义了如何构建模块,例如是否运行ProGuard;2、构建中包含哪些资源可以用到BuildType;3、Gradle为项目的产品风格和构建类型的每个可能组合创建一个构建变体。

两行代码 踏踏实实de工作 6704

腾讯面试——机器学习岗面试总结

先写合并两个有序数组,接着写合并n个有序的数组,假设总共m个数,讲了一个思路两两合并直到只剩下一个数组,分析一下时间复杂度(MlogN),面试官不满意,然后想了一下说了另一个思路,用n个指针开始指向各个数组的首端,用一个优先队列维护他们的最小值,每次拿出最小值的指针然后插入该指针的下一个值。感觉跟二面面试官聊得还是挺开心的,他详细地介绍了他们部门所做的业务,然后问了一下什么时候能来实现,我说只能暑假七八两个月,他觉得有点晚,这样子不利于转正,有些人都实习半年的,回去讨论一下,正式批之前给我答复。

FPGA/MATLAB学习教程/源码/项目合作开发 1231

Python 爬虫实战:深入同花顺,抓取股票行情数据,助力投资决策

通过本次 Python 爬虫实战,我们成功地从同花顺抓取了股票行情数据,并进行了存储、处理、分析和可视化展示。在这个过程中,我们不仅掌握了爬虫技术的基本应用,还学会了如何对动态加载的数据进行处理和分析。然而,本次爬虫任务也存在一些局限性,例如仅爬取了部分股票的数据,且未对股票的历史行情进行深入分析。在未来的工作中,我们可以进一步优化爬虫程序,爬取更多股票的数据,并深入分析股票的历史行情走势、技术指标等,为投资者提供更有价值的数据支持。

u014481728的博客 5334

快手java开发面试经验大全

1.自我介绍 2.java集合、hashmap详细介绍、关键参数、线程安全的集合、队列和栈、用两个栈实现队列算法 3.jvm结构 4.多线程锁:synchronized、reentrantlock、countdownlatch、锁升级 5.mysql隔离级别 6.线程池有哪些、核心参数、线程池运行机制 7.threadlocal 8.写线程安全单例模式,volatile原理、 9.写单词拆分问题 10.反问 好像叫基础平台部门。java岗。 总体来说,快手...

dadan的博客 9337

ABAP Secure Storage 在事务码 SM59 中的应用

系统管理人员在进行维护时,应关注相关日志信息,及时发现可能出现的安全异常,并针对不同安全等级的操作制定相应的备份与恢复策略,以降低潜在风险。该区域在设计上具备高度隔离性,仅允许经过授权的组件访问。保存后,系统会将密码存储在 Secure Storage 中,这种处理方式充分体现了 SAP 标准程序在安全设计上的考量。对于系统管理员而言,这种机制在日常维护与审计中提供了有力的支持,可以通过比对存储数据的哈希值或其他完整性校验手段,及时发现异常变动,保障系统长期稳定运行。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 675

15个顶级Java多线程面试题及答案

在我看来这是最好的java线程面试问题之一,它可以确切的检测候选者解决竞争条件的经验,or writing code which is free of data race or any other race condition。这个问题的回答应该是这样的,当你调用start()方法时你将创建新的线程,并且执行在run()方法里的代码。与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。这个java面试问题可以变的非常棘手,如果他要求你写一个不可变对象,或者问你为什么String是不可变的。

2301_78102191的博客 4758

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【多线程并发编程】六 什么是线程安全?

在学习多线程的道路上,我们会经常看到线程安全这类词汇,面试官也经常问,本文就来说一说什么是线程安全。

程序猿学社的博客 5817

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

熟记这99道Java多线程面试题,可以和面试官扯皮了!

点击上方“终端研发部”,选择“星标”回复“资源”,领取全网最火的Java核心知识总结~链接:https://www.jianshu.com/p/3e88a5fe75f0前言今天给大家更新...

这个时代,作为程序员可能要学习小程序 3491

面试官:多线程问题你一问三不知,还要我怎么“放水”?

面试官:问你几个多线程相关的问题吧,说一下导致线程死锁的原因,怎么解除线程死锁? 程序员阿里:这个...死锁... (一分钟后) 面试官:不知道?那好,说一下Lock 和 Synchronized 的区别? 程序员阿里:Lock是锁... 面试官:...会就会,不会就说不会,节省一下时间,sleep 和 wait 的区别总该知道吧? 程序员阿里:...不怎么了解 面试官:那多线程的几种实现方式,什么是线程安全,这总该知道吧? 程序员阿里:咱能换个技术点问吗? 面试官:连多线程并发你都一问三

Java6888的博客 1604

面试官:你连多线程问题你都清楚,还想要我怎么“放水”?

面试官:问你几个多线程相关的问题吧,说一下导致线程死锁的原因,怎么解除线程死锁? 程序员阿里:这个...死锁... (一分钟后) 面试官:不知道?那好,说一下Lock 和 Synchronized 的区别? 程序员阿里:Lock是锁... 面试官:...会就会,不会就说不会,节省一下时间,sleep 和 wait 的区别总该知道吧? 程序员阿里:...不怎么了解 面试官:那多线程的几种实现方式,什么是线程安全,这总该知道吧? 程序员阿里:咱能换个技术点问吗? 面试官:连多线程并发...

bieber007的博客 267

那些面试官必问的JAVA多线程和并发面试题及回答

Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了不同的类和程序的单一进程。线程可以被称为轻量级进程。线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源。 2. 多线程编程的好处是什么? 在多线程程序中,多个线程被并发的执行以提高程序的效率,CPU不会因为某个线程需要等待资源而进入空闲状态。多个线程共享堆内存(heap memor

weixin_46577306的博客 1115

java 多线程高级面试_15个顶级Java多线程面试题及答案

多线程和并发的问题是任何java面试中必不可少的一部分。1)现在有三个线程:T1、T2和T3。如何确保T2在T1完成后执行,T3在T2完成后执行?这个线程问题通常在第一阶段或电话面试阶段询问,以确定您是否熟悉“连接”方法。此多线程问题比较简单,可以在联接方法中实现。2)在java锁接口优势比同步块是什么?您需要实现一个高效的高速缓存,允许多个用户读取,但只允许一个用户写入,以保持其完整性。你是如何...

weixin_33322743的博客 1545

java面试题分享,15个java多线程面试题及答案

15个java多线程面试题及答案 Java,可以说学完基础才是真正的开始,成功面试也是程序员必须经历的一步。面试答题技巧是很重要的,又快又准确的回答,能让公司对你产生好感。下面是我归纳的一些java多线程的面试题和答题思路。 1、现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法...

Tyloo_wdnmd的博客 355

Java最新Java多线程一次给你整明白,详细解说

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录需要这份系统化的资料的朋友,可以点击这里获取Service9 }核心线程池为0,存活时间为60s,适合小而快的任务[外链图片转存中…(img-AdagCK6y-1715377374530)][外链图片转存中…(img-ztemel0i-1715377374531)][外链图片转存中…(img-BUaqvcep-1715377374532)]本文已被。

2401_84692456的博客 1062
上一篇: 【Java多线程手写代码】(二):利用多线程模拟动车票售卖
下一篇: 【Java多线程手写代码】(四):字节跳动面试官让我手写代码实现启动三个线程累加数字到30
少侠露飞
博客等级 码龄9年 214粉丝 117原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值