Java 递归/多线程程序问题

Java 递归/多线程程序问题,java,multithreading,recursion,Java,Multithreading,Recursion,我不熟悉Java和多线程。我有以下问题: 我有两个名为Class A和Class B的类,它们运行在两个不同的线程中 A类具有方法onNewEvent() 调用该方法后,它将要求类B执行一些工作。一旦类B完成了工作,它就会调用同样在类A中定义的方法onJobDone() 现在,问题来了:我想要的是在方法onJobDone()中创建一个新作业,并将其再次发送到类B 下面是我在执行序列中所做的(伪代码) A.onNewEvent(){ //create job //ask B to

我不熟悉Java和多线程。我有以下问题:

我有两个名为
Class A
Class B
的类,它们运行在两个不同的线程中

A类
具有方法
onNewEvent()

调用该方法后,它将要求
类B
执行一些工作。一旦类B完成了工作,它就会调用同样在类A中定义的方法
onJobDone()

现在,问题来了:我想要的是在方法
onJobDone()
中创建一个新作业,并将其再次发送到
类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()
,因此执行流永远不会到达代码的打印消息部分

我想这是一个令人讨厌的多线程问题


任何帮助都将不胜感激。

这不是多线程问题,您刚刚创建了一个无限循环。B.do调用A.onJobDone,后者调用B.do,后者调用A.onJobDone等,因此执行将永远不会到达打印消息行。您需要一个突破条件,以便在onJobDone中您可以决定是否要“doItAgain”。在某个时刻,您将决定不再执行此操作,此时您的代码将到达打印消息行


如果您描述一下您想要实现的目标,我们可能会给您一些关于实现它的最佳方法的建议,这可能会有所帮助。我不确定您试图解决问题的方法是否真的是最好的方法。

这不是多线程问题,您刚刚创建了一个无限循环。B.do调用A.onJobDone,后者调用B.do,后者调用A.onJobDone等,因此执行将永远不会到达打印消息行。您需要一个突破条件,以便在onJobDone中您可以决定是否要“doItAgain”。在某个时刻,您将决定不再执行此操作,此时您的代码将到达打印消息行

如果您描述一下您想要实现的目标,我们可能会给您一些关于实现它的最佳方法的建议,这可能会有所帮助。我不确定你试图解决问题的方法是否真的是最好的方法。

这里有一个建议

 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()
}这里有一个建议

 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()

}

调用类方法本身并不与线程绑定。换句话说,在线程1中调用
B.do()
内部
A.onNewEvent()
仍将在线程1中执行。换句话说,对象的方法可以从任何线程调用

要在给定线程中执行方法,需要在线程的
run
方法中调用该方法。为了支持这一点,您需要定义:B上的方法在有新作业时发出信号,B的一个字段用来保存作业信息(一般来说,您可以使用队列,但这里可以使用一个简单的整数),并正确地同步对B的字段的访问(可能在某个地方存在竞争条件或僵局),但我相信下面的方法应该可以奏效

要避免的主要问题是死锁。大多数同步方法不会导致死锁。
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();
        }
        ...
    }
}

调用类方法本身并不与线程绑定。换句话说,在线程1中调用
B.do()
内部
a.onNewEvent()
仍将在线程1中执行。换句话说,对象的方法可以从任何线程调用

要在给定线程中执行方法,您需要在线程的
run
方法中调用该方法。为了支持这一点,您需要定义:B上的方法在有新作业时发出信号,B上的字段保存作业信息(通常,您会使用队列,但这里可能使用简单的整数)并正确地同步对B字段的访问。自从我在Java中完成这项工作以来,已经有一段时间了(可能在某个地方存在争用条件或死锁),但我相信下面的方法应该可以工作

要避免的主要问题是死锁。大多数同步方法不会导致死锁。
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();
        }
        ...
    }
}

另一种方法是实现调用,将异步方法(
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
方法重构为实现该算法的类是另一种模式,但我不确定其名称。它不完全相同,也不完全相同。它几乎遵循该模式,但不完全相同。

另一种方法是实现调用,重构异步方法(
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
方法重构为实现该算法的类是另一种模式,但我不确定它的名称。它不完全是,也不是。它几乎遵循