Synchronizing Threads


For your project's thread safety, you want to be sure that threads don't harm each other. How you accomplish this depends largely on your architecture. I used a lock manager for locking database records. Because all database read/ writes were funneled through the lock manager, the responsibility for thread safety was logically placed in the lock manager. As it turns out, very little code was needed to make all this happen. All I had to do was synchronize the lock and unlock methods by adding the synchronize keyword in the method declaration. This ensured that only one thread could implement these methods at one time. What each method did was thread safe, so after I had the lock manager, I needed to type only two words to satisfy the thread safety requirement. Some candidates do too much when it isn't necessary.

graphics/tip_icon.gif

You should also be sure to check the classes bundled in the assignment download. If you study them, you'll see that they are already thread safe, so you shouldn't have to touch them if they're used properly.


You have seen how to use asynchronous threads, in which each thread is completely independent of all the others. What happens when there are dependencies between threads? How can you manage threads when more than one thread wants the same resource simultaneously ? This requires synchronizing threads, which means making sure one thread doesn't harm the others, and vice versa. Your solution must account for times when separate users concurrently attempt to reserve seats. This means several threads will try to read or save data to the database at the same time. You must not allow one user to write data to the database while another user is reading the same data, so you need to synchronize reading and writing data to the database. This synchronization code has a significant impact on the server portion of your final score.

You need to allow threads to share a common resource in a way that is not destructive to the data, so you must synchronize the various method calls. The approach Java uses is to "lock" a particular block (whether it is a whole method or just a block), funnel activity through that single block, and then synchronize the block, meaning all threads have to take turns using the block. That way, only one thread at a time can use it. This one-thread-at-a-time tactic prevents more than one thread from reading or writing data simultaneously. To lock a block or method, you use the synchronized keyword. Listing 10.3 later in this section includes the following code:

 class NewObject {     public void nextMethod()     {         System.out.println("NewObject.nextMethod() has executed.");     } } 

Notice that many threads can call nextMethod() concurrently. In this case, there is no harm because this method simply prints out a string. However, if this part of the code involved writing or reading data that another thread might change simultaneously, you risk one thread interfering with the other.

As mentioned, the way to prevent threads from stepping on each other is to synchronize a block of code so that only one thread at a time can change and read a given variable. Synchronization is especially helpful in database code. To synchronize the nextMethod() method shown previously, you would add the synchronize keyword in the method declaration, like so:

 class NewObject {     public synchronize void nextMethod()     {         System.out.println("NewObject.nextMethod() has executed.");     } } 

As you can see, synchronizing threads is easy in Java. You simply need to add the synchronize keyword. Listing 10.3 is a complete example of how to synchronize threads.

graphics/caution_icon.gif

Neglecting to add multithreading to your certification project is an automatic failure. Adding too much isn't good, either. As an attempt to add an insurance measure, some candidates synchronize (that is, declare a method with the synchronize keyword) too many things. However, this tactic causes you to lose points, not gain them. Be careful about what you synchronize.


Listing 10.3 Synchronizing Methods
 public class SynchronizedThreads {     public static void main( String [] args )     {         System.out.println( "Main Start" );         for(int i = 0; i < 10; i++)         {             // create a new thread             new ObjectOne().start();             new ObjectTwo().start();         }         System.out.println( "Main Done" );     } } // a new thread class class ObjectOne extends Thread {     static int counter = 1;     int me = 1;     public ObjectOne()     {         System.out.println("created ObjectOne # " + counter);         me = counter;         counter++;     }     // override the Thread.run method     public void run()     {         // sleep 0-10 seconds         int milliseconds =  (int)(Math.random() * (1000));         try         {             Thread.sleep(milliseconds);         // Oops, interrupted         } catch ( InterruptedException ex )         {            ex.printStackTrace();         }         System.out.println("Running ObjectOne # " + me + " but there are "                           + counter + " created.");         PrintObject printObject = new PrintObject();         printObject.incrementCounter();         printObject.printCounter();     } } // a new thread class class ObjectTwo extends Thread {     static int counter = 1;     int me = 1;     public ObjectTwo()     {         System.out.println("created ObjectTwo # " + counter);         me = counter;         counter++;     }     // override the Thread.run method     public void run()     {         // sleep 0-10 seconds         int milliseconds =  (int)(Math.random() * (1000));         try         {             Thread.sleep(milliseconds);         // Oops, interrupted         } catch ( InterruptedException ex )         {            ex.printStackTrace();         }         System.out.println("Running ObjectTwo # " +  me + " but there are "                           + counter + " created.");         PrintObject printObject = new PrintObject();         printObject.incrementCounter();         printObject.printCounter();     } } // a new thread class class PrintObject extends Thread {     static int counter = 1;     public PrintObject()     {         System.out.println("created PrintObject # " + counter);     }     public synchronized void incrementCounter() //     {         counter++;     }     public synchronized void printCounter()     {         System.out.println("PrintObject # " + counter);     } } /* results: Main Start created ObjectOne # 1 created ObjectTwo # 1 created ObjectOne # 2 created ObjectTwo # 2 created ObjectOne # 3 created ObjectTwo # 3 created ObjectOne # 4 created ObjectTwo # 4 created ObjectOne # 5 created ObjectTwo # 5 created ObjectOne # 6 created ObjectTwo # 6 created ObjectOne # 7 created ObjectTwo # 7 created ObjectOne # 8 created ObjectTwo # 8 created ObjectOne # 9 created ObjectTwo # 9 created ObjectOne # 10 created ObjectTwo # 10 Main Done Running ObjectTwo # 1 but there are 11 created. created PrintObject # 1 PrintObject # 2 Running ObjectOne # 6 but there are 11 created. created PrintObject # 2 PrintObject # 3 Running ObjectOne # 9 but there are 11 created. created PrintObject # 3 PrintObject # 4 Running ObjectTwo # 10 but there are 11 created. created PrintObject # 4 PrintObject # 5 Running ObjectTwo # 4 but there are 11 created. created PrintObject # 5 PrintObject # 6 Running ObjectOne # 1 but there are 11 created. created PrintObject # 6 PrintObject # 7 Running ObjectOne # 8 but there are 11 created. created PrintObject # 7 PrintObject # 8 Running ObjectTwo # 9 but there are 11 created. created PrintObject # 8 PrintObject # 9 Running ObjectTwo # 3 but there are 11 created. created PrintObject # 9 PrintObject # 10 Running ObjectOne # 3 but there are 11 created. created PrintObject # 10 PrintObject # 11 Running ObjectOne # 2 but there are 11 created. created PrintObject # 11 PrintObject # 12 Running ObjectOne # 5 but there are 11 created. created PrintObject # 12 PrintObject # 13 Running ObjectTwo # 5 but there are 11 created. created PrintObject # 13 PrintObject # 14 Running ObjectOne # 4 but there are 11 created. created PrintObject # 14 PrintObject # 15 Running ObjectOne # 10 but there are 11 created. created PrintObject # 15 PrintObject # 16 Running ObjectTwo # 7 but there are 11 created. created PrintObject # 16 PrintObject # 17 Running ObjectOne # 7 but there are 11 created. created PrintObject # 17 PrintObject # 18 Running ObjectTwo # 2 but there are 11 created. created PrintObject # 18 PrintObject # 19 Running ObjectTwo # 6 but there are 11 created. created PrintObject # 19 PrintObject # 20 Running ObjectTwo # 8 but there are 11 created. created PrintObject # 20 PrintObject # 21 */ 

Listing 10.3 demonstrates how easy it is to synchronize a method. In your locking mechanism, I recommend synchronizing the lock and unlock methods, or at least one method in the algorithm that all locks must carry out. That way, only one thread at a time can attempt to lock a record.

Synchronizing a method is a conservative tactic to protect it from thread problems. However, it does harm performance. A nice feature of Javave is the synchronized block which also prevents data corruption problems in multi-threaded Java programs. The advantage of the synchronized block is that it only protects the code in the block, not the entire method. It has the following structure:

 synchronized (myObject) {     //protected data and statements } 

The designers of Java figured out a way to protect objects; they associated a monitor for every object. When a thread finds a synchronized block, it automatically checks with that object's monitor to see if it is available. When the thread gets permission from the object's monitor, any subsequent thread request is put on hold until the current thread exits that synchronized block. At that point the monitor gives the next thread access to the synchronized block. Only one thread at a time may acquire a monitor, which guarantees that there will never be more than one thread at a time inside the block. If several blocks of code synchronize on the same object, then only one thread can be in the entire set of blocks.

Whether you synchronize the method or a block, the threads vying for access can have several states. The following API defines the various states a thread can take. For example, you can make a thread wait or notify other threads that are waiting for another one. Please note the thread methods as follows :

  • notify ” Wakes up one thread that is waiting on this object's monitor. The thread with the highest priority doesn't get chosen ; it is an arbitrary choice among the waiting threads.

  • notifyAll ” Wakes up all threads that are waiting on this object's monitor. The waiting threads compete for the next access.

  • wait ” Causes the current thread to wait until another thread calls notify() or notifyAll() on this object.

  • wait(long time) ” Causes the current thread to wait for the specified time or until another thread calls notify() or notifyAll() on this object.

Threads are a powerful feature in Java. They enable developers to manage what processes occur and when. Fortunately, managing threads is easy to do with the Java language. In your project, you need to synchronize access to the database because Sun specifically instructs you to make that portion of the assignment multiuser capable. All you must do is use the synchronize keyword for a few methods, and you have satisfied most of what is required for this part of the project. In particular, you have to implement a locking mechanism and make sure its methods are synchronized and thread safe.

My employer, Verizon Wireless, supports millions of customers who use the Web site to check their accounts, change their information, and purchase phones and accessories. Verizon's servers, which use Java to manage application logic, have a high volume of traffic. At times, multiple users cause the application layer to query the same database table simultaneously. To prevent users' queries from interfering with each other, transactions are synchronized using techniques similar to the ones described in this chapter.



JavaT 2 Developer Exam CramT 2 (Exam CX-310-252A and CX-310-027)
JavaT 2 Developer Exam CramT 2 (Exam CX-310-252A and CX-310-027)
ISBN: N/A
EAN: N/A
Year: 2003
Pages: 187

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net