我是Java和多线程的新手。我有以下问题:
我有两个名为Class A
和Class B
的类在两个不同的线程中运行。
Class A
的方法为onNewEvent()
。
调用该方法后,它会要求Class B
做一些工作。一旦B类完成工作,它就会调用onJobDone()
中定义的方法Class A
。
现在,问题就出现了:我想要的是在方法onJobDone()
中创建一个新工作,然后再将其发送到Class B
。
这是我在执行顺序中做的(伪代码)
A.onNewEvent(){
//create job
//ask B to do it
B.do()
}
B.do{
// Do some stuff
A.jobDone()
}
A.onJobDOne(){
B.do() //doItAgain
// print message "Thank you for doing it"
}
问题是“谢谢你这样做”的消息永远不会被打印出来。实际上,当调用onJobDone()
方法时,它会调用B.do()
,因为B.do()
非常快。它立即调用onJobDone()
,因此执行流程永远不会出现在代码的PRINT MESSAGE部分。
我认为这是一个令人讨厌的多线程问题。
任何帮助都将不胜感激。
答案 0 :(得分:3)
这不是一个多线程问题,你刚刚创建了一个无限循环。 B.do调用A.onJobDone调用B.do调用A.onJobDone等。因此执行永远不会到达打印消息行。你需要一个突破条件,以便在onJobDone中你可以决定你是否想要'doItAgain'。在某些时候,您将决定不再进行此操作,此时您的代码将到达打印消息行。
如果你描述了你想要实现的目标可能会有所帮助,我们可以给你一些关于实现它的最佳方法的指示。我不确定你试图解决问题的方式是不是最好的方式。
答案 1 :(得分:0)
这是一个建议
A.onNewEvent(){
//create job
//ask B to do it
B.do()
}
B.do{
// Do some stuff
A.onJobDone()
}
A.onJobDone(){
// print message "Thank you for doing it" (B.do() has just completed, so it
//will print for every time you call B.do()
if (shouldDoJobAgain()) //it should stop some time, right?
B.do()
}
答案 2 :(得分:0)
调用类方法并不固有地与线程相关联。换句话说,在线程1中调用B.do()
内的A.onNewEvent()
仍将在线程1中执行。换句话说,可以从任何线程调用对象的方法。
要在给定线程中执行方法,您需要在线程的run
方法中调用该方法。为了支持这一点,您需要定义:B上的方法,当有新作业时发出信号,B表示保存作业信息的字段(通常,您使用队列,但这里可以使用简单的整数)和正确地同步对B字段的访问。自从我在Java中完成此操作(可能存在竞争条件或某处死锁)以来,它已经有点了,但我相信以下应该工作
class A {
...
public void onEvent() {
b.addJob();
}
// careful about making onJobDone synchronized
public void onJobDone() {
// do it again
b.addJob();
...
}
}
class B extends Thread {
A a;
int jobCount;
boolean work;
...
public void run() {
shouldWork(true);
while (shouldWork()) {
while (haveJobs()) {
doingJob();
...
didJob();
}
waitForWork();
}
}
public synchronized void addJob() {
++jobCount;
notify();
}
protected synchronized boolean haveJobs() {
return jobCount > 0;
}
protected synchronized void doingJob() {
/* could also decrement 'jobCount' in didWork(), in which case
it will need to be made synchronized
*/
--jobCount;
}
protected void didJob() {
a.onJobDone();
}
protected synchronized void waitForWork() {
while (! haveJobs()) {
try {
wait();
} catch (Exception e) {
}
}
public synchronized void shouldWork(boolean w) {
work = w;
}
protected synchronized boolean shouldWork() {
return work;
}
}
要避免的主要问题是死锁。大多数同步方法不会导致死锁。 waitForWork
调用wait
,它会释放监视器,以便其他线程可以成功调用addJob
。
请注意,上述操作仍将永久运行,因为作业结束会导致安排新作业。与编码方式相比,优势在于A.onJobDone
将完成,您将不会获得堆栈溢出。如果您希望每个A.onEvent
使B处理n个作业,请将A
定义为:
class A {
int jobsPerEvent;
int remainingJobs;
...
public void onEvent() {
synchronized (this) {
remainingJobs += jobsPerEvent;
}
b.addJob();
}
public synchronized void jobsRemain() {
return remainingJobs > 0;
}
public void onJobDone() {
synchronized (this) {
--remainingJobs;
}
// do it again
if (jobsRemain()) {
b.addJob();
}
...
}
}
答案 3 :(得分:0)
另一种方法是实现asynchronous method调用,将异步方法(B.do
)重构为一个单独的类。
class B {
A a;
Set jobs;
class BAlgo extends Thread {
public void run() {
// stuff originally in B.do
...
done();
jobs.remove(this);
}
}
public void do() {
BAlgo algo = this.new BAlgo();
algo.start();
jobs.add(algo);
}
protected void done() {
a.onJobDone();
}
...
}
我确定将do
方法重构为实现算法的类是另一种模式,但我不确定它的名称。它不是bridge pattern,也不是template method pattern。它几乎遵循proxy模式,但并不完全。