When to manually sync Java threads and when not
In what cases you do not have to synchro开发者_开发问答nize to propagate data from one thread to another?
Try the Java Synchronization tutorial. It will walk you through the basics. Also realize that manually controlling threading via synchronization is slow and extremely error-prone. Other idioms (and languages) have evolved that shelter developers from the complexity of managing raw threads.
There are a few cases where you do not have to synchronize to propagate data from one thread to another, because the JVM is implicitly performing the synchronization for you.
These cases include:
- When data is initialized by a static initializer (an initializer on a static field or in a static{} block)
- When accessing final fields
- When an object is created before a thread is created
- When an object is already visible to a thread that it is then joined with
You don't need to use synchronization if your application has only a single thread (not counting the garbage collection thread, which is the VM's responsibility). Some libraries, such as Swing, introduce multi-threading, so you have to watch out.
I take your question to mean: "Why don't you just mark all methods synchronized" or "Why aren't all methods synchronized automatically"
If everything was synchronized, you would likely get no benefit from multi-threading. Multiple threads could be active, but only one at a time could progress through your code.
Also, synchronization imposes an overhead, which can be substantial, as the JVM checks the mutual exclusion lock.
If you can stick to one thread, you do not need to synchronize. If you need another thread, synchronizing everything to do with that thread is an easy way to avoid problems.
But, if you have multiple threads and want to get the most out of them, you want to do everything to can to avoid synchronizing. In that case, the only time you need to synchronize is when you have a set of fields that must be consistent with each other and when one or more of those fields might get accessed from another thread. Then, and only then, do you need a synchronization block.
Do note that any object of a non-thread-safe class contains a whole set of such fields, and must be synchronized even when used on its own:
private final Collection bigList;
synchronized (bigList) { // Protect bigList!
bigList.add( something );
}
There is also the case with only one field, such as:
private final int holderID;
if (holderID == 0) {
holderID = 2213;
// Do other stuff thinking that holderID equals 2213 and no one else will try
// to do the same other stuff, such as updating databases or writing to other
// fields.
}
This does need to be synchronized. Otherwise, 10,000 threads could all execute this line simultaneously (if your CPU had at least 10,000 cores), see a zero in holderID, set the value to their own number, and wreak havoc. However, since 1.5 you can use the java.util.concurrent.atomic package to avoid traditional, slow synchronization.
You do have to be very careful with minimally synchronized multi-threading. Read up, think hard, and devise tests that keep all your threads going for minutes at a time. Make every class and instance field that is not final volatile. Never trust a class or instance field. Get all values into local variables as soon as possible and keep them there as long as possible. For instance, do not do this:
if (mainList != null) mainList.get( 1 );
Some thread is bound to null mainList between the two references. You could synchronize it, but best to do:
MainList ml = mainList;
if (ml != null) ml = ml.get( 1 );
精彩评论