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();
}
...
}
}