IBM Java multithreading - 5. Sync Details

For more information synchronization
1. mutex
2. Visibility
3. What time must be synchronized?
4. Consistency for synchronizing
5. incrementing counter shared
6. invariance and final field
7. When no synchronization
8. deadlock
9. Performance Considerations
10. The synchronization criterion

Exclusive Page 1 (10 pages)


In shared access to data , we discuss the synchronizedfeatures of the block, and to achieve a typical mutex illustrates thereof (i.e., critical sections or mutexes), wherein only one thread may be performed by a given lock protection code block.

Mutex synchronization is an important part of the work done, but the synchronization with several other features that are very important to get the correct results on multiprocessor systems.

Visibility Page 2 (of 10)


In addition to mutual exclusion, synchronization (e.g. volatile) to force some visibility constraints. When the object is to acquire the lock, it first makes its own cache is invalid, so as to ensure variable load directly from the main memory.

Similarly, before the object the lock is released, it will refresh its cache, forced to make any changes have been made to appear in the main memory.

Thus, the two will ensure that seen in the same thread synchronization lock synchronizedthe same value in the modified block variables.

What time must be synchronized? Page 3 (total 10)


To maintain the correct cross-thread visibility, as long as the non-final variables shared between several threads, you must use synchronized(or volatile) to ensure that a thread can see changes made by another thread.

The basic rule is that the visibility of synchronization must be synchronized in the following cases:

  • The variable may be read once written by another thread
  • A variable that may be read by another thread under written

For consensus-based synchronization Page 4 (of 10)


In addition to visibility for synchronization, from the application point of view, you must also use synchronization to ensure consistency maintenance. When modifying multiple related values, you want to see other threads atom to which set of changes - all changes either see or not see anything. This applies to related data items (such as the location and velocity of particles) and the metadata items (e.g., data values ​​and a list of data items chain itself included in the list).

Consider the following example, which implements a simple (but not thread-safe) of a stack of integers:


public class UnsafeStack {
  public int top = 0;
  public int[] values = new int[1000];

  public void push(int n) {
    values[top++] = n;
  }

  public int pop() {
    return values[--top];
  }
}
          

If multiple threads attempt to use this class, what will happen? This could be a disaster. Because there is no synchronization, multiple threads can be executed simultaneously push()and pop(). If a thread calls push(), while another thread just incremented topand take it as a valuescall between subscript push(), what will happen? As a result, these two threads will their new value is stored in the same location! When multiple threads depend on the known relationship between the data values, but does not ensure that only one thread at a given time can operate those values may be many forms of data corruption, and this is just one of them.

In this case, the remedy is simple: synchronous push()and pop()both, you will prevent the thread execution interfere with each other.

Please note that volatilenot enough - need synchronizedto make sure topand valuesconsistent relationship between.

Share counter is incremented Page 5 (total 10)


In general, if you are protecting a fundamental variable (such as an integer), sometimes using only volatileyou can get away with. However, if the new value of the variable derived from the previous value, you must use synchronization. why? Consider this class:


public class Counter {
  private int counter = 0;

  public int  get()      { return counter; }
  public void set(int n) { counter = n; }
  public void increment() {
    set(get() + 1);
  }
}
          

When we want to increment the counter, what will happen? Look at increment()the code. It is clear, but not thread-safe. If two threads trying to simultaneously perform increment(), what would happen? Counter may increase 1, 2 may increase. Surprisingly, the countermarked volatiledoes not help to make get()and set()have become synchronizedno help.

Imagine counter is zero, and execute two threads simultaneously increment operation code. These two threads call Counter.get(), and see the counter is zero. Both threads are now a plus to it, and then call Counter.set(). If our timing is not coincidence, then the two threads could not see each other's updates, even counterShi volatile, or get()and set()Shi synchronized. Now, even if the counter is incremented twice, maybe just to get a value, instead of two.

To make the increment operation run properly, not only get(), and set()must be synchronized, and increment()must also be synchronized! Otherwise, calling increment()the thread may break another call increment()thread. If you are unlucky, the end result would be counter increased only once, not twice. Synchronization increment()prevents the occurrence of this situation, because the whole operation is atomic increment.

When loop through Vectorelement when same is true. Even if a synchronous Vectorapproach, but when looping through, Vectorthe content is still subject to change. If you want to make sure that Vectorthe contents do not change when looping through, you must synchronize the entire block of code.

Invariance and final field Page 6 (Total 10)


Many Java classes, including String, Integerand BigDecimalare immutable: Once constructed, their state will never change. If all fields of a class are declared final, then this class is immutable. (In fact, many immutable classes have a non-final fields, a method for caching the results of previous calculations, such as String.hashCode(), but the caller can not see these fields.)

Immutable class make concurrent programming very simple. Because you can not change their field, so you do not need to worry about the change in status is passed from one thread to another. When properly constructed object, you can see it as a constant.

Similarly, final field for the thread and more friendly. Because the final field after initialization, their values ​​can not be changed, so when the final field is shared between threads, do not worry about synchronizing access.

When no synchronization Page 7 (Total 10)

In some cases, you do not have to synchronize to pass data from one thread to another, because the JVM has performed for you sync implicitly. These include:

  • A static initializer (or on a static field static{}when the initializer block) initialization data
  • When accessing final fields
  • When you create an object before creating a thread
  • When the thread visible objects will be processed

Deadlock Page 8 (total 10)

As long as you have more than one process, and they want to fight with exclusive access to multiple locks, then there is a deadlock may occur. If there is a group of processes or threads, each of which are in operation only other waiting for a process or thread can perform, then they are said to deadlock the.

The most common form of deadlock when the lock on the threads holding the object 1 A, and is waiting for a lock on B and, while holding a lock on the object B 2 thread, but is waiting for a lock on the object A. These two threads never get a second lock or release the first lock. They just wait forever.

To avoid deadlock, you should ensure that when acquiring multiple locks are acquired lock in all the threads in the same order.

Performance Considerations Page 9 (Total 10)

About the performance costs of synchronization There are many claims - many of which are wrong. Synchronization, especially contention synchronization does have performance problems, but these problems are not as widespread skepticism about so much.

Many people are using ingenious tricks but does not work in an attempt to avoid having to use synchronous, but eventually fell into trouble. A typical example is the double-checked locking (See references , including several articles on this model have any questions). It is said that this seemingly innocuous synchronous structure can avoid common code path, but inexplicably failed, and all attempts to revise its attempt also failed.

When writing concurrent code, unless seen conclusive evidence of performance problems, do not give much thought to the performance. Bottlenecks most often occur in places we do not doubt. Perhaps a speculative optimized code path eventually will never be a performance problem - the cost of procedural correctness - is a money-losing business.

Synchronization Guidelines Page 10 (Total 10)

When writing synchronizedtime block, there are a few simple guidelines you can follow these guidelines go a long way in avoiding the risk of deadlock and performance risks:

  • Holding block so short. SynchronizedBlock should be short - ensure the integrity of data in operations while, as brief as possible. The thread does not vary with changes in pre- and post-out synchronizedblocks.
  • Do not block. Do not synchronizedcall the method may cause obstruction blocks or methods, such as InputStream.read().
  • When holding a lock, do not call a method on other objects. This may sound extreme, but it eliminates the most common source of deadlock.






 

Reproduced in: https: //www.cnblogs.com/licheng/archive/2008/09/23/1296819.html

Guess you like

Origin blog.csdn.net/weixin_33774883/article/details/92631616