In an object-based application, most objects are passive. A passive object just sits there waiting for one of its methods to be invoked. A passive object’s private member variables can only be changed by the code in its own methods, so its state remains constant until one of its methods is invoked. In a multithreaded environment like Java, threads can run within objects to make the objects active. Objects that are active make autonomous changes to themselves.
Sometimes in modeling a system, it becomes apparent that if some of the objects were active, the model would be simplified. Earlier in this book, classes that implemented Runnable were instantiated, passed to one of the constructors ofThread, and then start() was invoked. This style required a user of a class to know that a thread needed to be started to run within it, creating a burden on the user of the class. In addition, because the user of the class created theThread object for it, a reference to Thread was available for misuse. The user of the class could erroneously set the priority of the thread, suspend it at a bad time, or outright stop the thread when the object it was running in was in an inconsistent state. Having to activate objects externally is both inconvenient and potentially hazardous. In this chapter, I’ll show you how to have an active object transparently create and start up its own internal thread.
Simple Self-Running Class
The class SelfRun, shown in demonstrates a simple example of an active object. During construction, it automatically starts an internal thread running.
Code Listing SelfRun.java—A Simple Self-Running Class
1: public class SelfRun extends Object implements Runnable { 2: private Thread internalThread; 3: private volatile boolean noStopRequested; 4: 5: public SelfRun() { 6: // other constructor stuff should appear here first ... 7: System.out.println("in constructor - initializing..."); 8: 9: // Just before returning, the thread should be 10: // created and started. 11: noStopRequested = true; 12: internalThread = new Thread(this); 13: internalThread.start(); 14: } 15: 16: public void run() { 17: // Check that no one has erroneously invoked 18: // this public method. 19: if ( Thread.currentThread() != internalThread ) { 20: throw new RuntimeException("only the internal " + 21: "thread is allowed to invoke run()"); 22: } 23: 24: while ( noStopRequested ) { 25: System.out.println("in run() - still going..."); 26: 27: try { 28: Thread.sleep(700); 29: } catch ( InterruptedException x ) { 30: // Any caught interrupts should be habitually 31: // reasserted for any blocking statements 32: // which follow. 33: Thread.currentThread().interrupt(); 34: } 35: } 36: } 37: 38: public void stopRequest() { 39: noStopRequested = false; 40: internalThread.interrupt(); 41: } 42: 43: public boolean isAlive() { 44: return internalThread.isAlive(); 45: } 46: }