Version 8

    Writing Thread Safe Code

     

    Quick info on writing thread safe application code.  There are some tricks that can be used to avoid the need for Java object synchronization (see java.util.concurrent. or org.jboss. for examples), however, most applications should stick to the guidelines presented here.

     

     

    Definitions

     

    Mutable - an object that allows its member variables to be updated.  An instance of java.util.HashMap is mutable because its contents can be updated via put() + remove() method calls.  If a mutable Java object is shared between multiple threads, it needs to be protected with synchronization locks.

     

    Immutable Object_ - an object that does not allow its state to be changed.  An instance of java.util.String is immutable because its contents can not be updated.  If an immutable Java object is shared between multiple threads, it does not need to be protected. 

     

    Immutable Reference - an immutable reference to an object can only be assigned once (either during constructor or static initializer).  An immutable reference is always marked final.  You do not need to protect the reference when reading its value since its not going to change.  However, you need to protect the referenced object if it's mutable.  An example of this would be "final HashMap worldMap = new Hashmap()".  You need to protect the HashMap instance but not your class that contains the reference to the HashMap.

     

    Java Memory Model

     

    The designers of Java decided to handle concurrency as part of the language (c/c++ uses thread library API calls instead).  Java supports running on multi CPU systems which complicates what Java programmers have to face. 

     

     

    Lets take a brief tour down to the metal.

     

    Assuming a typical dual CPU machine.  On each clock cycle tick, each CPU will independently execute its current instruction.  The instruction might be reading/writing memory or a computation.

     

    When the CPU performs memory read/write operations, it may use the values already in the CPU cache.  It is typical for the CPU to execute more than one path through the &147;instruction stream&148; at a time (predicting what the outcome will be for both paths of a conditional operation). 

     

    The CPU designers also needed to design for concurrency so that programs will have a consistent view of memory.  When CPUs (predictively) execute multiple instruction streams in advance, they will only execute up to a fence or barrier which is identified by operands in the instruction stream. 

     

    Java is a slave to how CPUs handle multiprocessing (MP).  The Java designers are constrained by what the CPU designers allowed for (and &147;write once, run anywhere&148; promise).  The Java memory model supports running on various CPUs with varying MP implementations.

     

    As if the above isn't complicated enough, each CPU also has a private set of registers.  The CPU registers are like a fixed array of memory values and each array entry has a different name.  When the operating system scheduler switches execution to a new thread (context switch), the current thread registers are pushed onto the stack.  The registers may hold Java variables that haven't been written to main memory yet.  However, as long as the Java thread holds a synchronization lock until main memory is updated, everything is fine (main memory is updated when the lock is released).

     

     

    Memory Model Rules Summary

    The Java Language Specification defines the rules for when main memory is copied to thread memory and thread memory to main memory.  Think of thread memory as values held in cpu registers or cpu cache.

     

    1. A lock action acts as if it flushes all variables from the thread's working memory; before use, variables must be assigned or loaded from main memory.

    2. If a thread is to perform an unlock action on any lock, it must first copy all assigned values in its working memory (registers or processor cache) back out to main memory. 

    3. In the absence of explicit synchronization, the JVM is free to update the main memory in an order that may be surprising to the application. Therefore the programmer who prefers to avoid surprises should use explicit synchronization.

     

     

    Single Check Anti-pattern

     

    The single check, is simply, a variable test and allocation without any synchronization:

     

    public class JustGreat { // this is bad Java code
       private static MyComplexStuff m_stuff = null;
       public static MyComplexStuff getStuff() {
         if(m_stuff == null)
             m_stuff = new MyComplexStuff();
          return m_stuff;
       }
     }
    

     

    The above code may be perfectly fine in a single threaded client application but is a disaster in a multi threaded application. The above code should of synchronized before reading/writing the m_stuff variable or made m_stuff a 'static final':

     

    public class JustGreat {
       private static final MyComplexStuff STUFF = new MyComplexStuff();
       public static MyComplexStuff getStuff() {
          return STUFF;
    }
    

     

     

    Double Check Anti-Pattern

     

    Double check is:  variable test (read), synchronization lock, variable test and allocation.

     

    public class JustGreat {  // this is bad Java code
      private static MyComplexStuff m_stuff = null;
      public static MyComplexStuff getStuff() {
          if(m_stuff == null)// threads reads read m_stuff without locking
             synchronized(JustGreat.class) {
               if(m_stuff==null)
                  m_stuff = new MyComplexStuff();
             }
         
          return m_stuff;
      }
    }
    

     

    The above code should of synchronized before reading/writing the m_stuff variable or made m_stuff a 'static final'.

     

     

    Developing Thread Safe code

     

    Are Portal Portlet instance variables shared by all users or does each user get its own instance of the portlet?  The answer to this question is very telling.  A single Portlet instance can have many active users at the same time, and its variables are shared by all users of the Portlet instance. 

     

    If the Portlet instance variable can be read/written by multiple threads, it needs to be made safe.  This rule applies to any Java object, not just Portlets.  One way of protecting the instance variables is by surrounding read/write operations in a synchronization block. 

     

    It doesn't actually matter which object instance that you synchronize on, as long as both read and write operations synchronize on the same object instance.

     

     

    Atomic Operations and Isolation

     

    You may need to protect more than just the variable, you may need to ensure that the entire operation(s) involving the variable run in complete isolation to completion. 

     

    Public class  BankAccount {
      public BankAccount(AccountID yourAccount) {...}
      public void transferMoney(float amount, BankAccount destination) {
          balance -= amount;
          destination.balance +=amount;
          }
       public float getBalance() { return balance; }
       private float balance;
    }
    

     

    What happens if the 'destination' parameter is null above?  Your account balance will be decremented before the NullPointerException is thrown.  Also, what happens if the account balance is checked in the middle of the operation?  You either want the balance before the transfer started or after it completed. 

     

    Public class BetterBankAccount {
       public BetterBankAccount( AccountID yourAccount) {...}
       public synchronized void transferMoney(float amount, BankAccount destination) {
         boolean deposit = false;
         balance -= amount;   // this shouldn't fail (need to handle overdraft still)
         try {
              destination_balance += amount;
              deposit = true;
         } finally { if(!deposit) destination_balance -= amount;}  // rollback      
       }
       public synchronized void getBalance() { return balance; }
    

     

    We made the transfer atomic by assuring that it would either complete successfully or no changes will be made to the account balance.  The 'balance' variable is protected by the synchronization blocks that surround its access.

     

     

    Singletons objects

     

    When writing a singleton class, be careful not to use the single check or double check anti-patterns mentioned above.  The right way to code your singleton is with the reference as a static final to ensure that its only assigned once.

     

    public ChocolateProducer {
       private  ChocolateProducer() { // disable newing of this class
       public static ChocolateProducer getInstance() { return INSTANCE; }
       private static final INSTANCE = new  ChocolateProducer();
    }
    

     

    If you want to share an instance of the class but not enforce having the class be a singleton, make two classes.  ChocolateProducer will be normal (multiple instances allowed) class.  Introduce a  ChocolateProducerSingleton class.

     

    public ChocolateProducer { public  ChocolateProducer() {} ... }
    public final  ChocolateProducerSingleton { 
       private  ChocolateProducerSingleton() {}
       public  static ChocolateProducer getInstance() { return INSTANCE; }
       private static final INSTANCE = new  ChocolateProducer();
    }
    

     

    To be complete, the third approach is a lazy load technique.  In client side applications, it often the correct implementation, however, its wrong for server applications (calls to getInstance() may take a long time to return depending on the frequency of invocations).

    public final LazyLoadingGizmo {
       private  LazyLoadingGizmo() {}  
       public  synchronized static LazyLoadingGizmo getInstance() {
          if( instance == null)  instance = new  LazyLoadingGizmo();
          return instance;
        }
        private static  LazyLoadingGizmo instance;
    }
    

     

     

    Don't expose 'this' Object Reference Before Constructor Completes

     

    Java constructors shouldn't hand off a reference to 'this' to other objects until the constructor completes.  Other threads may see an inconsistent view of your object if you violate this rule.

     

    public class soccerPlayer {
        public soccerPlayer() {
            m_name = "Mia Hamm";
            m_gameRegistry.add(this);  // register player Mia Hamm (example of leaking 'this' from ctor)
            m_status = INJURED;
        }
    }
    

     

    In the above code fragment, the Mia Hamm soccer player is registered before her status is declared as INJURED.  She will play in the game when she should of been resting.  Instead, make the registration a separate step after the constructor runs.

     

    public class soccerPlayer {
        public soccerPlayer(String name, playerStatus status) {
            m_name = name;      
            m_status = status;
        }
    }
    
    soccerPlayer hamm = new  soccerPlayer("Mia Hamm", soccerPlayer.INJURED);
    registry.register(hamm);