|Access||Adobe photoshop||Algoritmi||Autocad||Baze de date||C||C sharp|
|Calculatoare||Corel draw||Dot net||Excel||Fox pro||Frontpage||Hardware|
|Php||Power point||Retele calculatoare||Sql||Tutorials||Webdesign||Windows|
|Asp||Autocad||C||Dot net||Excel||Fox pro||Html||Java|
A thread can be in any one of four states:
New: the thread object has been created but it hasnít been started yet so it cannot run.
Runnable: This means that a thread can be run when the time-slicing mechanism has CPU cycles available for the thread. Thus, the thread might or might not be running, but thereís nothing to prevent it from being run if the scheduler can arrange it; itís not dead or blocked.
Dead: the normal way for a thread to die is by returning from its run( ) method. You can also call stop( ), but this throws an exception thatís a subclass of Error (which means you usually donít catch it). Remember that throwing an exception should be a special event and not part of normal program execution; thus the use of stop( ) is discouraged (and itís deprecated in Java 1.2). Thereís also a destroy( ) method (which has never been implemented) that you should never call if you can avoid it since itís drastic and doesnít release object locks.
Blocked: the thread could be run but thereís something that prevents it. While a thread is in the blocked state the scheduler will simply skip over it and not give it any CPU time. Until a thread re-enters the runnable state it wonít perform any operations.
The blocked state is the most interesting and is worth further examination. A thread can become blocked for five reasons:
Youíve put the thread to sleep by calling sleep(milliseconds), in which case it will not be run for the specified time.
Youíve suspended the execution of the thread with suspend( ). It will not become runnable again until the thread gets the resume( ) message.
Youíve suspended the execution of the thread with wait( ). It will not become runnable again until the thread gets the notify( ) or notifyAll( ) message. (Yes, this looks just like number 2, but thereís a distinct difference that will be revealed.)
The thread is waiting for some IO to complete.
The thread is trying to call a synchronized method on another object and that objectís lock is not available.
You can also call yield( ) (a method of the Thread class) to voluntarily give up the CPU so that other threads can run. However, the same thing happens if the scheduler decides that your thread has had enough time and jumps to another thread. That is, nothing prevents the scheduler from re-starting your thread. When a thread is blocked, thereís some reason that it cannot continue running.
The following example shows all five ways of becoming blocked. It all exists in a single file called Blocking.java, but it will be examined here in discrete pieces. (Youíll notice the ďContinuedĒ and ďContinuingĒ tags that allow the tool shown in Chapter 17 to piece everything together.) First, the basic framework:
The Blockable class is meant to be a base class for all the classes in this example that demonstrate blocking. A Blockable object contains a TextField called state that is used to display information about the object. The method that displays this information is update( ). You can see it uses getClass( ).getName( ) to produce the name of the class instead of just printing it out; this is because update( ) cannot know the exact name of the class it is called for, since it will be a class derived from Blockable.
The indicator of change in Blockable is an int i, which will be incremented by the run( ) method of the derived class.
Thereís a thread of class Peeker that is started for each Blockable object, and the Peekerís job is to watch its associated Blockable object to see changes in i by calling read( ) and reporting them in its status TextField. This is important: Note that read( ) and update( ) are both synchronized, which means they require that the object lock be free.
The first test in this program is with sleep( ):
In Sleeper1 the entire run( ) method is synchronized. Youíll see that the Peeker associated with this object will run along merrily until you start the thread, and then the Peeker stops cold. This is one form of blocking: since Sleeper1.run( ) is synchronized, and once the thread starts itís always inside run( ), the method never gives up the object lock and the Peeker is blocked.
Sleeper2 provides a solution by making run un-synchronized. Only the change( ) method is synchronized, which means that while run( ) is in sleep( ), the Peeker can access the synchronized method it needs, namely read( ). Here youíll see that the Peeker continues running when you start the Sleeper2 thread.
The next part of the example introduces the concept of suspension. The Thread class has a method suspend( ) to temporarily halt the thread and resume( ) that re-starts it at the point it was halted. Presumably, resume( ) is called by some thread outside the suspended one, and in this case thereís a separate class called Resumer that does just that. Each of the classes demonstrating suspend/resume has an associated resumer:
SuspendResume1 also has a synchronized run( ) method. Again, when you start this thread youíll see that its associated Peeker gets blocked waiting for the lock to become available, which never happens. This is fixed as before in SuspendResume2, which does not synchronize the entire run( ) method but instead uses a separate synchronized change( ) method.
You should be aware that Java 1.2 deprecates the use of suspend( ) and resume( ), because suspend( ) holds the objectís lock and is thus deadlock-prone. That is, you can easily get a number of locked objects waiting on each other, and this will cause your program to freeze. Although you might see them used in older programs you should not use suspend( ) and resume( ). The proper solution is described later in this chapter.
The point with the first two examples is that both sleep( ) and suspend( ) do not release the lock as they are called. You must be aware of this when working with locks. On the other hand, the method wait( ) does release the lock when it is called, which means that other synchronized methods in the thread object could be called during a wait( ). In the following two classes, youíll see that the run( ) method is fully synchronized in both cases, however, the Peeker still has full access to the synchronized methods during a wait( ). This is because wait( ) releases the lock on the object as it suspends the method itís called within.
Youíll also see that there are two forms of wait( ). The first takes an argument in milliseconds that has the same meaning as in sleep( ): pause for this period of time. The difference is that in wait( ), the object lock is released and you can come out of the wait( ) because of a notify( ) as well as having the clock run out.
The second form takes no arguments, and means that the wait( ) will continue until a notify( ) comes along and will not automatically terminate after a time.
One fairly unique aspect of wait( ) and notify( ) is that both methods are part of the base class Object and not part of Thread as are sleep( ), suspend( ), and resume( ). Although this seems a bit strange at first Ė to have something thatís exclusively for threading as part of the universal base class Ė itís essential because they manipulate the lock thatís also part of every object. As a result, you can put a wait( ) inside any synchronized method, regardless of whether thereís any threading going on inside that particular class. In fact, the only place you can call wait( ) is within a synchronized method or block. If you call wait( ) or notify( ) within a method thatís not synchronized, the program will compile, but when you run it youíll get an IllegalMonitorStateException with the somewhat non-intuitive message ďcurrent thread not owner.Ē Note that sleep( ), suspend( ), and resume( ) can all be called within non-synchronized methods since they donít manipulate the lock.
You can call wait( ) or notify( ) only for your own lock. Again, you can compile code that tries to use the wrong lock, but it will produce the same IllegalMonitorStateException message as before. You canít fool with someone elseís lock, but you can ask another object to perform an operation that manipulates its own lock. So one approach is to create a synchronized method that calls notify( ) for its own object. However, in Notifier youíll see the notify( ) call inside a synchronized block:
where wn2 is the object of type WaitNotify2. This method, which is not part of WaitNotify2, acquires the lock on the wn2 object, at which point itís legal for it to call notify( ) for wn2 and you wonít get the IllegalMonitorStateException.
wait( ) is typically used when youíve gotten to the point where youíre waiting for some other condition, under the control of forces outside your thread, to change and you donít want to idly wait by inside the thread. So wait( ) allows you to put the thread to sleep while waiting for the world to change, and only when a notify( ) or notifyAll( ) occurs does the thread wake up and check for changes. Thus, it provides a way to synchronize between threads.
If a stream is waiting for some IO activity, it will automatically block. In the following portion of the example, the two classes work with generic Reader and Writer objects (using the Java 1.1 Streams), but in the test framework a piped stream will be set up to allow the two threads to safely pass data to each other (which is the purpose of piped streams).
The Sender puts data into the Writer and sleeps for a random amount of time. However, Receiver has no sleep( ), suspend( ), or wait( ). But when it does a read( ) it automatically blocks when there is no more data.
Both classes also put information into their state fields and change i so the Peeker can see that the thread is running.
The main applet class is surprisingly simple because most of the work has been put into the Blockable framework. Basically, an array of Blockable objects is created, and since each one is a thread, they perform their own activities when you press the ďstartĒ button. Thereís also a button and actionPerformed( ) clause to stop all of the Peeker objects, which provides a demonstration of the alternative to the deprecated (in Java 1.2) stop( ) method of Thread.
To set up a connection between the Sender and Receiver objects, a PipedWriter and PipedReader are created. Note that the PipedReader in must be connected to the PipedWriter out via a constructor argument. After that, anything thatís placed in out can later be extracted from in, as if it passed through a pipe (hence the name). The in and out objects are then passed to the Receiver and Sender constructors, respectively, which treat them as Reader and Writer objects of any type (that is, they are upcast).
The array of Blockable handles b is not initialized at its point of definition because the piped streams cannot be set up before that definition takes place (the need for the try block prevents this).
In init( ), notice the loop that moves through the entire array and adds the state and peeker.status text fields to the page.
When the Blockable threads are initially created, each one automatically creates and starts its own Peeker. So youíll see the Peekers running before the Blockable threads are started. This is essential, as some of the Peekers will get blocked and stop when the Blockable threads start, and itís essential to see this to understand that particular aspect of blocking.
Because threads can become blocked and because objects can have synchronized methods that prevent threads from accessing that object until the synchronization lock is released, itís possible for one thread to get stuck waiting for another thread, which in turn waits for another thread, etc., until the chain leads back to a thread waiting on the first one. Thus, thereís a continuous loop of threads waiting on each other and no one can move. This is called deadlock. The claim is that it doesnít happen that often, but when it happens to you itís frustrating to debug.
There is no language support to help prevent deadlock; itís up to you to avoid it by careful design. These are not comforting words to the person whoís trying to debug a deadlocking program.
One change that has been made in Java 1.2 to reduce the possibility of deadlock is the deprecation of Threadís stop( ), suspend( ), resume( ), and destroy( ) methods.
The reason that the stop( ) method is deprecated is because it is unsafe. It releases all the locks that the thread had acquired, and if the objects are in an inconsistent state (ďdamagedĒ) other threads can view and modify them in that state. The resulting problems can be subtle and difficult to detect. Instead of using stop( ), you should follow the example in Blocking.java and use a flag to tell the thread when to terminate itself by exiting its run( ) method.
There are times when a thread blocks, such as when it is waiting for input, and it cannot poll a flag as it does in Blocking.java. In these cases, you still shouldnít use stop( ), but instead you can use the interrupt( ) method in Thread to break out of the blocked code:
The wait( ) inside Blocked.run( ) produces the blocked thread. When you press the button, the blocked handle is set to null so the garbage collector will clean it up, and then the objectís interrupt( ) method is called. The first time you press the button youíll see that the thread quits, but after that thereís no thread to kill so you just see that the button has been pressed.
The suspend( ) and resume( ) methods turn out to be inherently deadlock-prone. When you call suspend( ), the target thread stops but it still holds any locks that it has acquired up to that point. So no other thread can access the locked resources until the thread is resumed. Any thread that wants to resume the target thread and also tries to use any of the locked resources produces deadlock. You should not use suspend( ) and resume( ), but instead put a flag in your Thread class to indicate whether the thread should be active or suspended. If the flag indicates that the thread is suspended, the thread goes into a wait using wait( ). When the flag indicates that the thread should be resumed the thread is restarted with notify( ). An example can be produced by modifying Counter2.java. Although the effect is similar, youíll notice that the code organization is quite different Ė anonymous inner classes are used for all of the listeners and the Thread is an inner class, which makes programming slightly more convenient since it eliminates some of the extra bookkeeping necessary in Counter2.java:
The flag suspended inside Suspendable is used to turn suspension on and off. To suspend, the flag is set to true by calling fauxSuspend( ) and this is detected inside run( ). The wait( ), as described earlier in this chapter, must be synchronized so that it has the object lock. In fauxResume( ), the suspended flag is set to false and notify( ) is called Ė since this wakes up wait( ) inside a synchronized clause the fauxResume( ) method must also be synchronized so that it acquires the lock before calling notify( ) (thus the lock is available for the wait( ) to wake up with). If you follow the style shown in this program you can avoid using wait( ) and notify( ).
The destroy( ) method of Thread has never been implemented; itís like a suspend( ) that cannot resume, so it has the same deadlock issues as suspend( ). However, this is not a deprecated method and it might be implemented in a future version of Java (after 1.2) for special situations in which the risk of a deadlock is acceptable.
You might wonder why these methods, now deprecated, were included in Java in the first place. It seems a clear admission of a rather significant mistake to simply remove them outright (and pokes yet another hole in the arguments for Javaís exceptional design and infallibility touted by Sun marketing people). The heartening part about the change is that it clearly indicates that the technical people and not the marketing people are running the show Ė they discovered a problem and they are fixing it. I find this much more promising and hopeful than leaving the problem in because fixing it would admit an error. It means that Java will continue to improve, even if it means a little discomfort on the part of Java programmers. Iíd rather deal with the discomfort than watch the language stagnate.
Politica de confidentialitate|
Adauga cod HTML in site