Immutable Objects Are Automatically Threadsafe Always Have a Safe Way to Stop Your Threads

Note that weve made a big trade-off here. In essence, weve replaced synchronous with asynchronous method calls to allow batching. This means that the return values arent meaningful. In addition, in our current framework theres no way to tell the client if something goes wrong™we cant throw a PrinterException after the method call has already returned. If the client really needs to know whether the print request succeeded, the client must either make a second method call later on to explicitly ask about the status of the print request or register for a callback. Well cover the latter technique in Chapt er 21 . You may have noticed that several of our threading principles are actually concrete versions of a abstract principle for organizing code: Things that are logically distinct should not interact with each other. Ensure Data Integrity was about preventing catastrophic interference. Minimize Time Spent in Synchronized Blocks was about reducing the amount of time distinct tasks spend waiting for each other to finish, and so on. Its apparent that Im a big fan of eliminating unneccesary interactions whenever, and wherever, possible. Even if it results in more code in the short-term, doing so will simplify debugging and long-term maintenance.

12.2.6 Immutable Objects Are Automatically Threadsafe

This is an obvious point that people often overlook. If you can guarantee that an objects state will never change, then you have guaranteed that the object is threadsafe. The String class, for example, is immutable. Once created, an instance of String does not change. Instead, methods such as concat have the following signature: public String concatString str This method returns a brand new string, which is the concatenation of the two older strings, both of which remain unchanged. This means that String is threadsafe. If we needed to, we could apply this to our Money class as well. The current implementation of subtract is: public void subtractMoney otherMoney { _cents -= otherMoney.getCents ; } This could easily be changed to: public Money subtractMoney otherMoney { int resultCents -= _cents - otherMoney.getCents ; return new Money resultCents; } If we performed a similar transformation on Money s add method, Money would become a threadsafe class, without a need to synchronize any of the methods or think about whether they are synchronized correctly. Of course, once weve changed Money , we must change our implementation of Account as well to reflect the new behavior. But have no fear. If we forget to do this, the testing framework well build in Chapt er 13 will help to detect the error. A special case of this rule of thumb is the stateless object; if an object has no state, its state cannot change. Hence, stateless objects are automatically threadsafe.

12.2.7 Always Have a Safe Way to Stop Your Threads

I mentioned this in Chapt er 11 . Threads, especially background threads, are usually set up to run for a very long period of time. For example, the lock expiration threads we implemented a few pages back ran in an infinite loop. Similarly, threads that automatically serialize objects to a datastore often run in the background in an infinite loop. Another example is a thread that automatically polls for external events, such as the thread in my mailreader that indefinitely checks for new mail every two minutes. What happens when you want to stop a thread? The Java language allows you to stop a thread simply by calling stop . However, as we discussed in Chapt er 11 , this method is deprecated, and doing so can leave your program in an inconsistent state. Its much better to use a boolean stop variable in your run method. Implement your run method as a loop that only continues if the stop variable is set correctly. The following code snippet is from Chapt er 11 , but its worth repeating: public abstract class StoppableThread extends Thread { ... many constructors, weve only included one public StopppableThreadString threadName, Object arg1, OObject arg2 { superthreadName; use arg1, arg2, ... to initialize thread state start ; } private boolean _shouldStopExecuting; public void setShouldStopExecutingboolean shouldStopExecuting { _shouldStopExecuting = shouldStopExecuting; } public boolean getShouldStopExecuting { return _shouldStopExecuting; } public void run { while _shouldStopExecuting { performTask ; } } protected abstract void performTask ; }

12.2.8 Background Threads Should Have Low Priority