我正在使用应用程序逻辑线程和数据库访问线程创建Java应用程序 . 它们都在应用程序的整个生命周期中持续存在,并且两者都需要同时运行(一个与服务器通信,一个与用户通信;当应用程序完全启动时,我需要它们都可以工作) .
但是,在启动时,我需要确保最初应用程序线程等待,直到db线程准备就绪(当前通过轮询自定义方法 dbthread.isReady()
确定) . 我不介意app线程阻塞,直到db线程准备好 .
Thread.join()
看起来不像解决方案 - 数据库线程仅在应用程序关闭时退出 .
while (!dbthread.isReady()) {}
有点工作,但空循环消耗了大量的处理器周期 .
还有其他想法吗?谢谢 .
13 回答
java.lang.concurrent
包中的Future接口旨在提供对在另一个线程中计算的结果的访问 .看看FutureTask和ExecutorService是否有现成的做这种事情的方法 .
我强烈建议阅读Java Concurrency In Practice对任何对并发和多线程感兴趣的人 . 它显然集中在Java上,但是对于任何使用其他语言的人来说都有很多东西 .
我真的建议你在开始多线程的神奇世界之前先阅读像_2665632这样的教程 .
还有很多好书(google为“Java中的并发编程”,“实践中的Java并发”) .
To get to your answer:
在必须等待
dbThread
的代码中,您必须具有以下内容:在
dbThread
的方法中,你需要做这样的事情:我在这些示例中使用的
objectYouNeedToLockOn
优选地是您需要从每个线程并发操作的对象,或者您可以为此目的创建单独的Object
(我不建议使方法本身同步):To further your understanding:
还有其他(有时更好的)方法来完成上述工作,例如:与
CountdownLatches
等等 . 自Java 5以来,java.util.concurrent
包和子包中有很多漂亮的并发类 . 你真的需要在网上找到材料来了解并发性,或者获得一本好书 .使用CountDownLatch,计数器为1 .
现在在app线程中 -
在db线程中,完成后,执行 -
要求::
答案::
任务完成!!见下面的例子
该程序的输出::
您可以看到在完成任务之前需要6秒,这比其他线程更大 . 所以Future.get()等待任务完成 .
如果你不使用future.get(),它不会等待完成并执行基于时间的消耗 .
祝你好运与Java并发 .
像这样使用这个类:
创建一个ThreadEvent:
在方法中,这是等待结果:
在创建所有结果后创建结果的方法中:
EDIT:
(很抱歉编辑这篇文章,但这段代码的竞争状况非常糟糕,我没有足够的声誉来评论)
如果您100%确定在await()之后调用signal(),则只能使用此方法 . 这就是为什么你不能使用像Java这样的Java对象的一个重要原因 . Windows事件 .
如果代码按此顺序运行:
那么 thread 2 will wait forever . 这是因为Object.notify()只唤醒当前正在运行的线程之一 . 稍后等待的线程不会被唤醒 . 这与我期望事件工作的方式非常不同,在事件发出信号之前,a)等待或b)显式重置 .
注意:大多数情况下,您应该使用notifyAll(),但这与上面的“永远等待”问题无关 .
尝试使用
java.util.concurrent
包中的CountDownLatch类,它提供更高级别的同步机制,远比任何低级别的东西都容易出错 .你可以使用两个线程之间共享的Exchanger对象来完成它:
在第二个帖子中:
正如其他人所说,不要采取这种轻松的,只是复制粘贴代码 . 先做一些阅读 .
很多正确的答案,但没有一个简单的例子..这是一个简单而简单的方法如何使用
CountDownLatch
:如果你想要快速和脏的东西,你可以在你的while循环中添加一个Thread.sleep()调用 . 如果数据库库是您无法更改的,那么实际上没有其他简单的解决方案 . 轮询数据库直到准备好等待时间不会导致性能下降 .
几乎没有什么可以称为优雅的代码,但完成工作 .
如果您可以修改数据库代码,那么使用其他答案中建议的互斥锁会更好 .
这适用于所有语言:
您想拥有一个事件/侦听器模型 . 您创建一个等待特定事件的侦听器 . 该事件将在您的工作线程中创建(或发出信号) . 这将阻止线程,直到接收到信号而不是不断轮询以查看是否满足条件,就像您当前拥有的解决方案一样 .
您的情况是导致死锁的最常见原因之一 - 确保您发出其他线程的信号,而不管可能发生的错误 . 示例 - 如果您的应用程序抛出异常 - 并且从不调用该方法来通知另一个事情已完成 . 这将使其他线程永远不会“醒来” .
我建议您在实现案例之前,先了解使用事件和事件处理程序的概念,以便更好地理解这个范例 .
或者,您可以使用互斥锁使用阻塞函数调用 - 这将导致线程等待资源空闲 . 要做到这一点,您需要良好的线程同步 - 例如:
您可以从一个线程中的阻塞队列中读取并在另一个线程中写入它 .
以来
join()
已被排除您已经使用CountDownLatch和
Future.get()已由其他专家提出,
您可以考虑其他替代方案:
ExecutorService
Executors
(自Java 8发布以来)这个想法可以适用吗?如果您使用CountdownLatches或Semaphores工作完美,但如果您正在寻找面试的最简单答案,我认为这可以适用 .