|
JDC Tech Tips Vol. 2 No. 2
September 15, 1998
|
|
Welcome to the JavaSM Developer ConnectionSM Tech Tips. This issue covers using synchronized statements and finally clauses. The JDC Team-
JDC Tech Tips
Using Synchronized Statements. Suppose that you're experimenting with JavaTM language threads, and you write a simple program such as the following:
When you run this program, you get output like the following: 1 2 3 4 5 6 7 8 9 9 10 11 13 14 15 16 17 18 19 20 Two instances of "9" occur, and none of "12" occur. Your results may vary from this output, which is the whole point of this example. Such results are "impossible," because "n" is incremented immediately after printing its value, isn't it? How can the same value be printed twice, or another value omitted altogether? The reason that this type of output can occur has to do with the nature of thread programming. In the following sequence:
with two threads executing, nothing says that these two statements must be executed atomically (that is, without any interruption between statements) within one thread, without the other thread gaining control. For example, a sequence such as the following:
To solve this problem, the example can be rewritten as follows:
This technique typically goes by the name of "critical sections," that is, regions of a program that can be safely executed by only one thread at a time. In this example, a class variable named "critsect" is set up, and used together with the "synchronized" statement to lock the region of code within the { } against simultaneous access. This procedure guarantees that the I/O statement and the following increment are performed atomically for a particular thread, before another thread is allowed to perform the same operations. Also, another type of synchronization is the synchronized instance method. In this method, the whole method is protected against simultaneous access, based on obtaining a lock on the "this" reference to the particular class instance being operated upon by the method. Finally Clauses. You may have seen the try...catch statement used in exception handling. With such a statement, a block of code is tried (executed), and any exceptions thrown as a result are directed to the various catch clauses. This type of statement also supports the use of a "finally" clause, which is a block of code that is executed whether or not the try block completes normally, results in an exception, or exits the containing method. A finally clause is therefore useful as a cleanup mechanism, and try...finally can be used without catch, and without specifically using exceptions. To see how all this works, consider the construction of a simple method, one that copies one file to another. The method should accept two file names, and propagate out any IOException that occurs (rather than trapping it internally). Here is some code that implements this idea, along with a driver program:
The driver exercises a particular aspect of this programming problem, that of gracefully handling repeated errors. In this example, the error is an invalid output file for the copy (an attempt is made to copy to "."). The copy method does not require a try...catch statement, because it propagates out the exception, and declares it in a throws clause. But what happens if copy is repeatedly called, with an invalid output file argument, after the FileInputStream for the input file has been successfully established? What can happen is a resource leak, with operating system file descriptors being allocated and eventually depleted. This situation is not the same as a memory leak, but instead simply reflects a failure to call close on the FileInputStream. Garbage collection will result in the finalize method being called for FileInputStream, and it calls close, but there's no guarantee that garbage collection will be invoked in a timely way. So the second copy invocation in the example above, one that is supplied valid arguments, fails without the try...finally. To fix this problem, a try...finally statement is used. No matter what happens in copy, the finally clause will be invoked, and it will close any open input stream. In this way, a finally clause can be used as a general cleanup mechanism.
-- Editor's Note -- The names on the JDC mailing list are used for internal Sun MicrosystemsTM purposes only. To remove your name from the list, see Subscribe/Unsubscribe below.
|
|
|
|||
|
|
| Questions? 18-Sep-98 Copyright © 1996-1998 Sun Microsystems Inc. All Rights Reserved. Legal Terms. Privacy Policy. | |