Invoking a class method isn't inherently tied to a thread. In other words, calling B.do() inside A.onNewEvent() in thread 1 will still execute in thread 1. In other other words, methods of an object can be invoked from any thread.
To have a method execute within a given thread, you'll need to call that method within the thread's run method. To support this, you'll need to define: methods on B that signal when there's a new job, a field of B to hold job information (in general, you'd use a queue, but a simple integer might work here) and properly synchronize access to the fields of B. It's been a little bit since I've done this in Java (there might be a race condition or deadlock somewhere), but I believe something like the following should work.
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;
}
}
The main problem to avoid is deadlock. Most of the synchronized methods won't cause deadlock. waitForWork calls wait, which releases the monitor so other threads can successfully call addJob.
Note that the above will still run forever, since the end of a job causes a new job to be scheduled. The advantages over how you've coded it is that A.onJobDone will finish and you won't get a stack overflow. If you want each A.onEvent to cause B to handle n jobs, define A as:
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();
}
...
}
}