Java多线程并发控制:解决相同key的线程互斥问题
作者:大大醯_804_224 | 来源:互联网 | 2024-12-25 14:15
本文探讨了在Java多线程环境下,如何确保具有相同key值的线程能够互斥执行并按顺序输出结果。通过优化代码结构和使用线程安全的数据结构,我们解决了线程同步问题,并实现了预期的并发行为。
在Java多线程编程中,确保多个线程之间正确、有序地执行是一个常见的挑战。本文将通过一个具体案例,详细讲解如何实现当多个线程调用同一方法时,如果传递的key相等,则这些线程需要互斥排队输出结果。 ### 问题描述 现有程序同时启动了4个线程去调用`TestDo.doSome(key, value)`方法,该方法内部先暂停1秒,然后再输出以秒为单位的当前时间值。由于所有线程几乎同时启动,因此会打印出相同的时间值。例如: ``` 4:4:1258444892 1:1:1258444892 3:3:1258444892 1:2:1258444892 ``` ### 需求分析 为了确保具有相同key值的线程能够互斥执行并按顺序输出结果,我们需要对代码进行修改。具体来说,当两个或多个线程的key相等时,它们应该依次输出结果,且每个线程比前一个线程晚1秒输出;而不同key值的线程则可以并行执行。 ### 解决方案 我们可以通过引入一个线程安全的集合来存储key值,并在`doSome`方法中使用互斥锁来确保相同key值的线程能够互斥执行。以下是具体的实现步骤: 1. **使用线程安全的集合**:为了避免在遍历集合时出现线程不安全的问题,我们可以使用`CopyOnWriteArrayList`,它是一个线程安全的集合。 2. **互斥锁的实现**:对于每个key值,我们使用一个唯一的对象作为互斥锁。如果多个线程的key值相同,则它们将共享同一个互斥锁对象,从而确保它们按顺序执行。 ### 修改后的代码 ```java package cn.edu.hpu.test; import java.util.concurrent.CopyOnWriteArrayList; public class ThreadTest9 extends Thread { private TestDo testDo; private String key; private String value; public ThreadTest9(String key, String key2, String value) { this.testDo = TestDo.getInstance(); this.key = key + key2; this.value = value; } public static void main(String[] args) { ThreadTest9 a = new ThreadTest9("1", "", "1"); ThreadTest9 b = new ThreadTest9("1", "", "2"); ThreadTest9 c = new ThreadTest9("3", "", "3"); ThreadTest9 d = new ThreadTest9("4", "", "4"); System.out.println("begin:" + (System.currentTimeMillis() / 1000)); a.start(); b.start(); c.start(); d.start(); } public void run() { testDo.doSome(key, value); } } class TestDo { private TestDo() {} private static TestDo _instance = new TestDo(); private CopyOnWriteArrayList keys = new CopyOnWriteArrayList<>(); public static TestDo getInstance() { return _instance; } public void doSome(String key, String value) { Object o = key; if (!keys.contains(o)) { keys.add(o); } else { for (String k : keys) { if (k.equals(o)) { o = k; break; } } } synchronized (o) { try { Thread.sleep(1000); System.out.println(key + ":" + value + ":" + (System.currentTimeMillis() / 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } } ``` ### 结果验证 通过上述修改,运行多次后可以观察到,具有相同key值的线程能够按顺序输出结果,而不同key值的线程则可以并行执行。例如: ``` 4:4:1258444892 1:1:1258444892 3:3:1258444892 1:2:1258444896 ``` 这种实现方式不仅解决了线程同步问题,还提高了程序的稳定性和可读性。
推荐阅读
本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ...
[详细]
蜡笔小新 2024-12-27 18:51:49
golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ...
[详细]
蜡笔小新 2024-12-28 13:47:52
本文探讨了 Objective-C 中的一些重要语法特性,包括 goto 语句、块(block)的使用、访问修饰符以及属性管理等。通过实例代码和详细解释,帮助开发者更好地理解和应用这些特性。 ...
[详细]
蜡笔小新 2024-12-26 19:42:38
本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ...
[详细]
蜡笔小新 2024-12-26 17:34:42
本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ...
[详细]
蜡笔小新 2024-12-26 16:06:09
本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ...
[详细]
蜡笔小新 2024-12-28 10:51:55
本文探讨了Java中类成员的初始化顺序、静态引入、可变参数以及finalize方法的应用。通过具体的代码示例,详细解释了这些概念及其在实际编程中的使用。 ...
[详细]
蜡笔小新 2024-12-27 19:39:42
1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ...
[详细]
蜡笔小新 2024-12-27 19:32:17
主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ...
[详细]
蜡笔小新 2024-12-27 18:18:10
本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ...
[详细]
蜡笔小新 2024-12-27 11:30:44
本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ...
[详细]
蜡笔小新 2024-12-27 10:28:40
本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ...
[详细]
蜡笔小新 2024-12-26 22:04:19
Java 中 Writer flush()方法,示例 ...
[详细]
蜡笔小新 2024-12-28 06:41:52
Java 中的 BigDecimal pow()方法,示例 ...
[详细]
蜡笔小新 2024-12-27 20:54:03
1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ...
[详细]
蜡笔小新 2024-12-27 18:36:54
大大醯_804_224
这个家伙很懒,什么也没留下!