线程练习题

news2024/10/5 20:20:27

有三个线程,分别只能打印A,B和C,要求按顺序打印ABC,打印10次

输出示例:

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

(1)、这种方法并不能达到题目要求,因为无法确认当线程A在打印完一次后释放锁并唤醒其他线程时,它会唤醒线程B和线程C中的哪一个。这就导致,线程的执行顺序可能是ACB,也可能是其他顺序。

public class Demo25 {

    public static void main(String[] args) {
        final Object lock = new Object();
        Thread a = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.print("A");
                    lock.notifyAll();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread b = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.print("B");
                    lock.notifyAll();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread c = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (lock) {
                    System.out.println("C");
                    lock.notifyAll();
                    try {
                        if (i < 9) {
                            lock.wait();
                        }
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        a.start();
        b.start();
        c.start();
    }
}

(2)、我们刚刚写的代码中的线程因为没有合适的条件判断从而不能够按相应的顺序打印字母,又因为没有终止条件,所以无法正常停止。

现在改进以上错误,重新写一个实现方法:


public class Thread_1{

    // 计数器
    // 定义一个单独的锁对象
    
    private static volatile int COUNTER = 0;
    private static Object lock = new Object();
   
    public static void main(String[] args) {
        // 创建三个线程,并指定线程名,每个线程名分别用A,B,C表示
        Thread t1 = new Thread(() -> {
            // 循环10次
            for (int i = 0; i < 10; i++) {
                // 执行的代码加锁
                synchronized (lock) {

                    // 每次唤醒后都重新判断是否满足条件
                    // 每条线程判断的条件不一样,注意线程t1,t2

                    while (COUNTER % 3 != 0) {
                        try {
                            // 不满足输出条件时,主动等待并释放锁
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    // 满足输出条件,打印线程名,每条线程打印的内容不同
                    System.out.print(Thread.currentThread().getName());
                    // 累加计数
                    COUNTER++;
                    // 唤醒其他线程
                    lock.notifyAll();
                }
            }
    }, "A");//线程被命名为 "A"

    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                while (COUNTER % 3 != 1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(Thread.currentThread().getName());
                COUNTER++;
                lock.notifyAll();
            }
        }
    }, "B");

    Thread t3 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {
                while (COUNTER % 3 != 2) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //换行打印
                System.out.println(Thread.currentThread().getName());
                COUNTER++;
                lock.notifyAll();
            }
        }
    }, "C");

    // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

代码 Thread_1 停下来的原因是每个线程都在循环中执行一定次数,并且使用了 lock.wait() 来等待条件满足。当满足条件后,线程会继续执行,否则会等待。

具体来说,代码中的三个线程 t1、t2、t3 会依次执行,它们之间使用了 lock 对象来同步,确保每次只有一个线程可以进入临界区执行。每个线程都有自己的条件检查,例如 t1 检查 COUNTER % 3 是否等于 0,t2 检查 COUNTER % 3  是否等于 1,t3 检查 COUNTER % 3  是否等于 2。这些条件控制了线程的执行顺序,确保了按照 “ABCABCABC” 的顺序输出。

当线程执行完一轮后,会通过 lock.wait() 主动释放锁并等待唤醒,然后其他线程会继续执行,直到满足条件后再次唤醒等待的线程。这种方式保证了线程的有序执行。

总之,这个代码中的线程之间使用了条件判断和等待来控制执行顺序,因此能够正常停止。

3、还有一种实现方法,就是使用三个锁, 分别控制。

public class Demo26 {
    private static Object locker1 = new Object();
    private static Object locker2 = new Object();
    private static Object locker3 = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker1) {
                        locker1.wait();
                    }
                    System.out.print("A");
                    synchronized (locker2) {
                        locker2.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker2) {
                        locker2.wait();
                    }
                    System.out.print("B");
                    synchronized (locker3) {
                        locker3.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    synchronized (locker3) {
                        locker3.wait();
                    }
                    //注意,只有C是println
                    System.out.println("C");
                    synchronized (locker1) {
                        locker1.notify();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t3.start();

        Thread.sleep(1000);

        // 从线程 t1 启动
        synchronized (locker1) {
            locker1.notify();
        }
    }
}

 

再来看道题吧,和上面的差不多。

有三个线程,线程名称分别为:a,b,c。每个线程打印自己的名称。

需要让他们同时启动,并按 c,b,a 的顺序打印。

public class PrintOrderDemo {
    private static final Object lock = new Object();
    private static volatile int turn = 0;

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 2) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("a");
                    turn = 0;
                    lock.notifyAll();
                }
            }
        });

        Thread threadB = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 1) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("b");
                    turn = 2;
                    lock.notifyAll();
                }
            }
        });

        Thread threadC = new Thread(() -> {
            while (true) {
                synchronized (lock) {
                    while (turn != 0) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    System.out.println("c");
                    turn = 1;
                    lock.notifyAll();
                }
            }
        });

        threadA.start();
        threadB.start();
        threadC.start();
    }
}

 

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

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

相关文章

ChatGPT AIGC 实现Excel行列多条件交叉查找

查找函数在Excel中一直是非常重要的知识点,我们让ChatGPT AIGC来总结一下关于查找函数的优点与了处。 Excel中的查找函数是一种非常强大且多用途的工具,具有以下优点和作用: 1. 数据定位:查找函数可以帮助我们在大量数据中快速定位某个特定的数据或信息。 2. 数据整理:如…

sql注入之高权限注入和文件读写

死在山野的风里&#xff0c;活在自由的梦里 sql注入之高权限注入 高权限注入1.多个网站共享mysql服务器2.MySQL 权限介绍3.注入流程查询所有数据库名称查询表名对应的字段名查询数据 文件读写1.文件读写注入的原理2.文件读写注入的条件3.读取文件4.写入文件 高权限注入 在数据…

linux jenkins2.414.1-1.1版本安装

文章目录 前言一、rpm文件下载二、安装jenkins2.1.升级jdk1.82.2安装jenkins2.3 启动服务2.4 使用密码登录2.5 修改插件源2.6 汉化插件安装演示 总结 前言 之前也安装过jenkins&#xff0c;但是那个版本是2.1的&#xff0c;太老了很多插件都不支持&#xff0c;现在安装目前为止…

2022年全国研究生数学建模竞赛华为杯D题PISA架构芯片资源排布问题求解全过程文档及程序

2022年全国研究生数学建模竞赛华为杯 D题 PISA架构芯片资源排布问题 原题再现&#xff1a; 一、背景介绍 芯片是电子行业的基础&#xff0c;在当前日益复杂的国际形势下&#xff0c;芯片成了各个大国必争的高科技技术。本课题关注网络通信领域的交换芯片&#xff0c;传统的交…

5.5G的技术原理和应用场景

引言 5.5G即5G-Advanced&#xff0c;是一种移动通信技术。 这个解释显然十分的boring&#xff0c;但是在5.5G还未正式进入大家生活的今天&#xff0c;这是百度词条给出为数不多的解释。 当今社会&#xff0c;移动通讯已成为人们生活中不可缺少的一部分。2G打开了文本时代&…

C/C++ 代码中使用 CMake 工程目录

C/C 代码中使用 CMake 工程目录 文章目录 C/C 代码中使用 CMake 工程目录使用原因如何使用参考链接 使用原因 在 C 代码中获取工程路径有点麻烦&#xff0c;因为如果生成的可执行文件(.exe) 位置与工程目录不同&#xff0c;则当前的路径为运行时的路径&#xff0c;可能需要通过…

H.265 视频在浏览器中的播放问题探究

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

华为OD机考算法题:MVP争夺战

目录 题目部分 解读与分析 代码实现 题目部分 题目MVP争夺战难度易题目说明在星球争霸篮球赛对抗赛中&#xff0c;强大的宇宙战队&#xff0c;希望每个人都能拿到MVP。 MVP的条件是&#xff0c;单场最高分得分获得者&#xff0c;可以并列&#xff0c;所以宇宙战队决定在比赛…

【Axure高保真原型】桥梁监控大屏可视化案例

今天和大家分享桥梁监控大屏可视化案例的原型模板&#xff0c;包括桥梁预警次数统计、预警类型分析、实时预警分析、通行趋势分析、通行类型分析、热门桥梁分析&#xff0c;里面包含多个高保真的图表模板&#xff08;多柱状图组、滚动列表、多面积图、排名图、玫瑰图&#xff0…

(未完成)【Redis专题】一线大厂Redis高并发缓存架构实战与性能优化

前言 在本章内容里&#xff0c;我希望大家还是要先看看【前置知识】的内容。按照我的大纲设计&#xff0c;我是想先给大家抛出一些大家比较陌生的&#xff0c;关于【Redis缓存问题以及缓存方案】的一些名词概念&#xff0c;再然后在正文【课程内容】里面给大家使用源码案例&am…

SQL9 查找除复旦大学的用户信息

描述 题目&#xff1a;现在运营想要查看除复旦大学以外的所有用户明细&#xff0c;请你取出相应数据 示例&#xff1a;user_profile iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543female20北京大学Beijing42315female23浙…

postman连接websocket, 建立连接、聊天测试(v8.5.1)

1. postman v8.5版本 以上支持 websocket。 2. 选择websocket请求模块File - New... 3. WebSocketServer.java import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.Server…

ChatGPT提示词(prompt)资源汇总

文章目录 awesome-chatgpt-promptsLearn PromptingSnack PromptFlow GPTPrompt VineChatGPT 指令大全AI Toolbox HubAI Short ChatGPT是一种强大的生成式AI模型&#xff0c;而提示词&#xff08;prompt&#xff09;则是与ChatGPT一起使用的指导性文本&#xff0c;用于引导模型生…

Redis的用法及面试题(删除策略、企业级解决方案)

目录 一、Redis删除策略 &#xff08;1&#xff09;过期数据 &#xff08;2&#xff09;数据删除策略 1.定时删除 2.惰性删除 &#xff08;3&#xff09;逐出算法 二、企业级解决方案 &#xff08;1&#xff09;缓存预热 &#xff08;2&#xff09;缓存雪崩 &…

【Spring面试】八、事务相关

文章目录 Q1、事务的四大特性是什么&#xff1f;Q2、Spring支持的事务管理类型有哪些&#xff1f;Spring事务实现方式有哪些&#xff1f;Q3、说一下Spring的事务传播行为Q4、说一下Spring的事务隔离Q5、Spring事务的实现原理Q6、Spring事务传播行为的实现原理是什么&#xff1f…

神经网络 07(正则化)

一、正则化 在设计机器学习算法时不仅要求在训练集上误差小&#xff0c;而且希望在新样本上的泛化能力强。许多机器学习算法都采用相关的策略来减小测试误差&#xff0c;这些策略被统称为正则化。因为神经网络的强大的表示能力经常遇到过拟合&#xff0c;所以需要使用不同形式的…

第4章_freeRTOS入门与工程实践之开发板使用

本教程基于韦东山百问网出的 DShanMCU-F103开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id724601559592 配套资料获取&#xff1a;https://rtos.100ask.net/zh/freeRTOS/DShanMCU-F103 freeRTOS系列教程之freeRTOS入…

Charles的Map Remote功能

1、charles的Map Remote功能&#xff08;指定的网络请求重定向到另一个网址&#xff09;&#xff0c;说白了就是你本来要请求A接口拿数据&#xff0c;重定向后&#xff0c;你实际请求的是B接口&#xff0c;拿到的是B接口返回的数据。 入口Tools->Map Remote 本次测试过程中…

【教程】IDEA操作GIT

不小心推送代码之后 进行回退 1 找到需要回退的记录 比如要回退13分钟之前提交的代码 选中 右键还原提交 最后再重新推送被还原的提交 就可以了

78基于matlab的BiLSTM分类算法,输出迭代曲线,测试集和训练集分类结果和混淆矩阵,程序有详细注释,数据可更换自己的,程序已调通,可直接运行。

基于matlab的BiLSTM分类算法&#xff0c;输出迭代曲线&#xff0c;测试集和训练集分类结果和混淆矩阵&#xff0c;程序有详细注释&#xff0c;数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 78 matlabBiLSTM模式识别混淆矩阵 (xiaohongshu.com)https://www.…