Re: merging two independant Java programs into one Java program running
two threads?
On 10/27/2014 9:33 AM, John wrote:
Hi:
I have two independent Java programs. Program A is a GUI program. Program B continuously take screen shots every 5 seconds and save them into PNG picture files.
Right now, I start running Java Program B first, then start Program A, doing GUI interaction etc.
I hope to merge the two into one Java program which runs the original two programs by two interdependent processes or threads(not sure which one is correct. Help please). And I would like to have this feature: when GUI interaction by me proceeds to certain stage, e.g. when I click Button 'XYZ' on the GUI, the process/thread taking screen shots halts. After a while, when I click another button, the halted process/thread proceeds again. At the end, when I quit the GUI program, the process/thread taking the screen shots ends as well.
I think this makes me learn multi-thread programming or inter-process communication. If you could shed some light on this project, I would greatly appreciate it.
This can be done with two threads or with two processes. (The
distinction: Two threads can run in the same Java Virtual Machine in
one process, or two processes each with its own JVM can run one thread
apiece.) It will be easier with two threads in one JVM, because it's
easier to communicate between activities in the same JVM than to chat
with an activity in a different JVM.
Either way, though, the notion of "independent programs" is not
tenable. You want Program B's behavior to depend on the state of
Program A, which it could not do if they were independent. Program B
needs to be made aware of what's going on in A, or else it can't know
when to collect screen captures and when to sit idle.
There are many ways to arrange the behavior you describe, but I
think the simplest might be for A to maintain a public field that
describes its own state: running (hey, look at me!), hidden (no
peeking, please), or finished:
enum State { RUNNING, HIDDEN, FINISHED };
class StateHolder {
private State current;
synchronized void setState(State newState) {
current = newState;
notifyAll(); // in case someone's in wait()
}
synchronized State getState() {
return current;
}
}
class A {
...
public final StateHolder state = new StateHolder();
...
// A is starting and allows B to view it:
state.setState(RUNNING);
...
// A wants some privacy:
state.setState(HIDDEN);
...
// A is about to stop running:
state.setState(FINISHED);
...
}
Meanwhile, class B can run on a Timer (or similar) that executes
it every five seconds regardless of what A is doing -- *except* that
each time B runs it checks A's status:
class B implements Runnable {
private final A myPartner;
...
public B(A partner) {
this.myPartner = partner;
...
}
...
@Override
public void run() {
// Arrange to have the Timer (or whatever) execute this
// method periodically.
synchronized (myPartner.state) {
while (myPartner.state.getState() == State.HIDDEN) {
myPartner.state.wait(); // ... for notifyAll()
}
if (myPartner.state.getState() == State.FINISHED) {
// A's finished; B should now finish, too.
}
}
// A is neither HIDDEN nor FINISHED, hence RUNNING:
// do the screen capture and return, then let the Timer
// re-execute "by and by."
}
...
}
This is a very basic -- some might say "crude" -- way to accomplish
your goal, and there are many others with different characteristics and
different degrees of sophistication. You might choose to do things a
little differently from what I've shown. For example, if the B above
finds its A in the HIDDEN state it blocks until the state changes to
something else, probably disrupting the regularity of the timed events.
You might instead decide to have B simply return if A is HIDDEN, the
idea being that the Timer will re-awaken it soon for another try. It
depends what you want ...
--
esosman@comcast-dot-net.invalid