- 浏览: 35076 次
- 性别:
- 来自: 南京
-
最新评论
问题的描述
启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到打印到75. 程序的输出结果应该为:
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程1: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9
线程2: 10
...
线程3: 71
线程3: 72
线程3: 73
线程3: 74
线程3: 75
解法一: 采用原始的synchronized, wait(), notify(), notifyAll()等方式控制线程.
解法二: 采用JDK1.5并发包提供的Lock, Condition等类的相关方法控制线程.
总结: 对比解法一和解法二, 显然解法二是更好的解决方案. 解法一的问题在于无法进行精确唤醒, 比如线程1执行完打印任务并调用pn.notifyAll()方法后, 3个线程将再次竞争锁, 而不是精确唤醒线程2. 虽然线程2最终将赢得锁, 下一次的打印任务也肯定会由线程2执行, 但是竞争的持续时间是不可预知的, 只能看线程2的人品.
最糟糕的情形可以是: 线程3竞争到了锁, 紧接着wait. 接下来线程1也竞争到了锁, 然后线程1也wait. 此时就再也没有其他线程跟线程2竞争了, 线程2终于艰难的赢得了锁...
留下3个问题供有兴趣的朋友思考:
1. 解法一和解法二中的while (state != xx)是否可以换成if(state != xx), 为什么?
2. 解法一的中的pn.notifyAll()是否可以换成pn.notify(), 为什么?
3. 是否可以用wait(), notify(), notifyAll()等方法完成类似解法二的精确唤醒, 请给出方案或代码.--这个问题我思考了很久, 却没有头绪. 关键的困难在于必须调用pn的wait()方法和notifyAll()方法, 而不能是其他对象的wait()和notifyAll()方法. 如果你有思路, 还望在博客中留言, 不甚感激!
启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5, 然后是线程2打印6,7,8,9,10, 然后是线程3打印11,12,13,14,15. 接着再由线程1打印16,17,18,19,20....以此类推, 直到打印到75. 程序的输出结果应该为:
线程1: 1
线程1: 2
线程1: 3
线程1: 4
线程1: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9
线程2: 10
...
线程3: 71
线程3: 72
线程3: 73
线程3: 74
线程3: 75
解法一: 采用原始的synchronized, wait(), notify(), notifyAll()等方式控制线程.
public class NumberPrintDemo { // n为即将打印的数字 private static int n = 1; // state=1表示将由线程1打印数字, state=2表示将由线程2打印数字, state=3表示将由线程3打印数字 private static int state = 1; public static void main(String[] args) { final NumberPrintDemo pn = new NumberPrintDemo(); new Thread(new Runnable() { public void run() { // 3个线程打印75个数字, 单个线程每次打印5个连续数字, 因此每个线程只需执行5次打印任务. 3*5*5=75 for (int i = 0; i < 5; i++) { // 3个线程都使用pn对象做锁, 以保证每个交替期间只有一个线程在打印 synchronized (pn) { // 如果state!=1, 说明此时尚未轮到线程1打印, 线程1将调用pn的wait()方法, 直到下次被唤醒 while (state != 1) try { pn.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // 当state=1时, 轮到线程1打印5次数字 for (int j = 0; j < 5; j++) { // 打印一次后n自增 System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); // 线程1打印完成后, 将state赋值为2, 表示接下来将轮到线程2打印 state = 2; // notifyAll()方法唤醒在pn上wait的线程2和线程3, 同时线程1将退出同步代码块, 释放pn锁. // 因此3个线程将再次竞争pn锁 // 假如线程1或线程3竞争到资源, 由于state不为1或3, 线程1或线程3将很快再次wait, 释放出刚到手的pn锁. // 只有线程2可以通过state判定, 所以线程2一定是执行下次打印任务的线程. // 对于线程2来说, 获得锁的道路也许是曲折的, 但前途一定是光明的. pn.notifyAll(); } } } }, "线程1").start(); new Thread(new Runnable() { public void run() { for (int i = 0; i < 5; i++) { synchronized (pn) { while (state != 2) try { pn.wait(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) { System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); state = 3; pn.notifyAll(); } } } }, "线程2").start(); new Thread(new Runnable() { public void run() { for (int i = 0; i < 5; i++) { synchronized (pn) { while (state != 3) try { pn.wait(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) { System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); state = 1; pn.notifyAll(); } } } }, "线程3").start(); } }4
解法二: 采用JDK1.5并发包提供的Lock, Condition等类的相关方法控制线程.
public class NumberPrint implements Runnable { private int state = 1; private int n = 1; // 使用lock做锁 private ReentrantLock lock = new ReentrantLock(); // 获得lock锁的3个分支条件 private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); @Override public void run() { new Thread(new Runnable() { public void run() { for (int i = 0; i < 5; i++) { try { // 线程1获得lock锁后, 其他线程将无法进入需要lock锁的代码块. // 在lock.lock()和lock.unlock()之间的代码相当于使用了synchronized(lock){} lock.lock(); while (state != 1) try { // 线程1竞争到了lock, 但是发现state不为1, 说明此时还未轮到线程1打印. // 因此线程1将在c1上wait // 与解法一不同的是, 三个线程并非在同一个对象上wait, 也不由同一个对象唤醒 c1.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 如果线程1竞争到了lock, 也通过了state判定, 将执行打印任务 for (int j = 0; j < 5; j++) { System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); // 打印完成后将state赋值为2, 表示下一次的打印任务将由线程2执行 state = 2; // 唤醒在c2分支上wait的线程2 c2.signal(); } finally { // 打印任务执行完成后需要确保锁被释放, 因此将释放锁的代码放在finally中 lock.unlock(); } } } }, "线程1").start(); new Thread(new Runnable() { public void run() { for (int i = 0; i < 5; i++) { try { lock.lock(); while (state != 2) try { c2.await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) { System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); state = 3; c3.signal(); } finally { lock.unlock(); } } } }, "线程2").start(); new Thread(new Runnable() { public void run() { for (int i = 0; i < 5; i++) { try { lock.lock(); while (state != 3) try { c3.await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int j = 0; j < 5; j++) { System.out.println(Thread.currentThread().getName() + ": " + n++); } System.out.println(); state = 1; c1.signal(); } finally { lock.unlock(); } } } }, "线程3").start(); } public static void main(String[] args) { new NumberPrint().run(); } }4
总结: 对比解法一和解法二, 显然解法二是更好的解决方案. 解法一的问题在于无法进行精确唤醒, 比如线程1执行完打印任务并调用pn.notifyAll()方法后, 3个线程将再次竞争锁, 而不是精确唤醒线程2. 虽然线程2最终将赢得锁, 下一次的打印任务也肯定会由线程2执行, 但是竞争的持续时间是不可预知的, 只能看线程2的人品.
最糟糕的情形可以是: 线程3竞争到了锁, 紧接着wait. 接下来线程1也竞争到了锁, 然后线程1也wait. 此时就再也没有其他线程跟线程2竞争了, 线程2终于艰难的赢得了锁...
留下3个问题供有兴趣的朋友思考:
1. 解法一和解法二中的while (state != xx)是否可以换成if(state != xx), 为什么?
2. 解法一的中的pn.notifyAll()是否可以换成pn.notify(), 为什么?
3. 是否可以用wait(), notify(), notifyAll()等方法完成类似解法二的精确唤醒, 请给出方案或代码.--这个问题我思考了很久, 却没有头绪. 关键的困难在于必须调用pn的wait()方法和notifyAll()方法, 而不能是其他对象的wait()和notifyAll()方法. 如果你有思路, 还望在博客中留言, 不甚感激!
发表评论
-
javaTrim方法扩展:Trim掉指定字符
2017-01-04 09:45 662public static String myTrim(Str ... -
Java中使用C3P0连接池
2017-01-03 16:09 3551、c3p0.properties c3p0.driv ... -
Java四种线程池的使用
2016-12-23 17:25 496Java通过Executors提供四种线程池,分别为: new ... -
JAVA在线编译器模拟
2016-12-23 16:54 517有很多网站提供在线编� ... -
jvm内存分析
2016-12-23 09:26 399http://www.cnblogs.com/ITtangta ... -
面向对象三大基本特性,五大基本原则
2016-12-18 21:40 311透切理解面向对象三大基本特性是理解面向对象五大基本原则的基础. ... -
接口和抽象类有什么区别
2016-12-18 21:38 411接口和抽象类有什么区别 你选择使用接口和抽象类的依据是什么? ... -
使用Java线程并发库实现两个线程交替打印的线程题
2016-12-12 11:22 503背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一 ... -
推荐书目与知识点记录
2016-12-08 19:38 3961、Java序列化 2、线程通信:比如最简单的2个线程轮流 ... -
maven初次使用问题记录
2016-03-15 21:59 467【1】下载安装 下载的免安装版本,直接配置maven_ho ... -
eclipse远程调试Tomcat方法
2016-03-15 19:18 5461、Linux中配置tomcat在catalina.sh中添 ... -
Excel导入MySql数据库批量操作
2015-12-31 10:07 1671最近在帮朋友做一个计时提醒系统,大致业务如下: 某 ...
相关推荐
这种系统将CPU的时间划分为时间片,轮流分配给各个用户进程,使每个用户感觉像是在独占计算机。 3. **操作系统的用户视角**:从用户角度看,操作系统是用户与计算机硬件之间的接口,它提供了一种简单易用的方式来...
在多线程或多进程环境中,为了保证资源的正确使用,需要确保同一时间只有一个进程能够访问临界资源。 - **选项A**: 实现进程互斥的代码属于互斥机制的一部分,不是临界区本身。 - **选项B**: 实现进程同步的代码...
系统选用B/S模式,后端应用springboot框架,前端应用vue框架, MySQL为后台数据库。 本系统基于java设计的各项功能,数据库服务器端采用了Mysql作为后台数据库,使Web与数据库紧密联系起来。 在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。
useTable(1).ts
内容概要:本文介绍了Matlab实现基于DBN-SVM(深度置信网络和支持向量机)的数据分类预测方法及其应用。首先,背景部分阐述了当前信息技术环境下,深度学习在多个领域的重要性及DBN和SVM各自的优势。文中详细描述了项目的目标与意义,包括实现DBN与SVM的联合优化、提升分类性能、扩展DBN应用领域及增强数据预处理与特征选择的能力。接着指出了项目面临的几大挑战,比如DBN的训练难度、高维数据处理、SVM参数选择等问题。项目的特点与创新在于充分利用了两种技术的优点,在自动化特征提取和精确分类等方面表现出色。最后探讨了该项目在金融、医疗、智能制造、自然语言处理及物联网等多个领域的具体应用案例,并给出了相关模型架构和技术实现细节。 适用人群:具备机器学习基础知识的研发人员,特别是对DBN和SVM有一定了解的研究人员和技术爱好者。 使用场景及目标:旨在解决数据分类预测任务,特别是在面对高维数据或小样本情况时需要提升分类准确性的问题;同时也适用于希望减少手动特征工程工作量的专业人士。目标是在复杂的数据集中提供更加可靠的预测解决方案,以应对诸如金融风险评估、医疗影像诊断、工业设备维护等领域内的具体业务挑战。 其他说明:提供的Matlab代码示例包括DBN-SVM模型的基本配置及训练过程,便于使用者根据实际情况调整参数设置。此外还包括了一些关于如何评估模型效果的方法,如通过可视化工具监测训练过程中损失值和准确度的变化趋势。
基于Carsim与Simulink联合仿真的汽车ESP系统单侧双轮制动控制模型与说明,汽车ESP系统仿真建模及控制方法研究:基于carsim与simulink联合仿真的单侧双轮制动,汽车ESP系统仿真建模,基于carsim与simulink联合仿真做的联合仿真,采用单侧双轮制动的控制方法。 有完整的模型和说明 ,汽车ESP系统仿真建模; 基于carsim与simulink联合仿真; 单侧双轮制动控制方法; 完整模型与说明。,基于CarSim与Simulink联合仿真的汽车ESP系统单侧双轮制动建模研究
爱分析2024智慧灯塔照亮企业AIAgent实施的明路应用实践报告35页.pdf
系统选用B/S模式,后端应用springboot框架,前端应用vue框架, MySQL为后台数据库。 本系统基于java设计的各项功能,数据库服务器端采用了Mysql作为后台数据库,使Web与数据库紧密联系起来。 在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。
更多毕业设计https://cv2022.blog.csdn.net/article/details/124463185
单LEO多天线单天线多用户.docx
“1990-2019年城市的绿色专利申请量和授权量”数据集覆盖中国地级市及以上城市在绿色技术创新领域的专利活动。该数据整合了国家知识产权局及WIPO标准筛选的绿色专利信息,包含发明专利、实用新型专利等类型,重点涵盖能源节约、污染控制、可再生能源等绿色技术领域。 数据显示,中国绿色专利授权量在近30年间呈现显著增长趋势。以2016-2021年为例,中国绿色低碳专利授权量年均增长6.5%,其中氢能、储能等领域增速尤为突出(如氢能领域年均增长20.5%),且北京、江苏、广东等省市领跑全国,合计占全国总量的30.1%。城市层面,绿色专利布局与区域产业政策密切相关,例如长三角、珠三角地区因新能源产业集聚,相关专利密度较高。 该数据为研究绿色技术创新的时空分布特征、政策驱动效应及国际竞争力提供了基础支撑,尤其适用于分析“双碳”目标下地方绿色技术转型的路径与成效。
UDEC7.0煤层建模开挖全代码实例详解:逐段逐句剖析与高效学习模板,UDEC7.0煤层建模全代码实例及详解:事半功倍的开采位移应力裂隙发育研究学习模板,UDEC7.0煤层建模开挖全代码实例+逐段逐句讲解。 非常好的学习模板,让你事半功倍,迅速的分析研究煤层开采位移 应力 裂隙的发育规律。 部分讲解见第3张图。 ,UDEC7.0煤层建模; 开挖全代码实例; 逐段逐句讲解; 学习模板; 煤层开采位移; 应力裂隙发育规律,UDEC7.0煤层建模全代码实例与详解
chromedriver-mac-x64-136.0.7055.0.zip
深度解析:利用动力学仿真数据绘制的滚动轴承分布图制作技术——百分之百博主亲笔编程代码详解,根据滚动轴承动力学仿真数据精准出图:博主原创设计程序,详尽注释助你轻松获取多维分布曲线变换图,根据已知的滚动轴承动力学仿真数据 出图。 程序百分百为博主亲自设计的,代码注释很详细,根据你的仿真数据使用我的程序就可以得到这样的效果。 可以出承载区与非承载区的1载荷分布、2摩擦力分布、3打滑率分布等各种时域变角度域分布曲线变图。 ,1. 滚动轴承动力学仿真数据; 2. 程序; 3. 载荷分布; 4. 摩擦力分布; 5. 打滑率分布; 6. 时域变角度域分布图。,基于滚动轴承仿真数据的图形化分析与处理程序
本数据集主要整合了 Middlebury2014 以及自建的 RGB 训练集,用于深度图像超分辨率及相关视觉任务研究。其中,Middlebury2014 数据集体量较大,包含高质量的立体对、深度图及配套标注信息,适合进行深度估计、立体匹配与超分辨率等多种实验;RGB TRAIN 则为针对深度超分所准备的配套 RGB 数据,可与深度图进行联合训练或引导。整体数据规模在数 GB 级别,覆盖多样场景和视角,能够支持深度学习模型在深度重建、融合超分和立体匹配等方向的深入研究与评测。
《绝热压缩空气储能系统:基于EBSILON 13.02的文献研究与分析》,《绝热压缩空气储能系统:基于EBSILON 13.02的文献研究与分析》,绝热压缩空气储能系统 带文献 ebsilon13.02 ,绝热压缩空气储能系统; 带文献; EBSILON 13.02;,绝热压缩空气储能系统:基于文献的Ebsilon13.02研究
昆仑通泰MCGS 7.7嵌入版仿真程序:六层电梯的优先级控制与管理系统,昆仑通泰MCGS 7.7嵌入版仿真程序:六层电梯控制,带优先级设置功能,6六层电梯昆仑通泰mcgs7.7嵌入版仿真程序带优先级 ,六层; 电梯; 昆仑通泰; mcgs7.7; 嵌入版; 仿真程序; 优先级,昆仑通泰MCGS 7.7六层电梯仿真程序带优先级
LabVIEW与TensorFlow深度学习:高效调用的实践教程,LabVIEW深度学习实践:基于TensorFlow框架的调用与应用教程,labview调用TensorFlow深度学习教程 ,LabView; TensorFlow; 深度学习; 调用教程,LabView深度集成TensorFlow教程
信捷PLC电子凸轮追剪飞剪样例程序:适用于枕式包装机的运动控制与技术解析。,信捷PLC电子追剪凸轮样例程序:基于XDH-60T4系列PLC的枕式包装机飞剪与电子凸轮控制策略详解,信捷PLC电子追剪凸轮样例程序 信捷XDH-60T4系列plc 基于枕式包装机开发的追剪,飞剪程序 飞剪滚切,PLC,运动控制,电子凸轮 信捷 电子凸轮追剪飞剪资料 多产品配方程序 A1517信捷PLC电子追剪凸轮样例程序 ,信捷PLC; 电子追剪凸轮样例程序; XDH-60T4系列PLC; 追剪飞剪程序; 运动控制; 飞剪滚切; 电子凸轮; 多产品配方程序; A1517信捷资料。,信捷PLC:多产品配方电子追剪凸轮与飞剪程序样例(XDH-60T4系列)
更多毕业设计https://cv2022.blog.csdn.net/article/details/124463185