Thread Basics Series (iii) synchronization of threads

Source: Internet
Author: User

This article is the third of the series, the previous 2, mainly for a single thread How to manage, start, etc., there is not too much involved in how multiple threads work together.

Thread Basics Series (ii) thread management: Thread state, control, hibernation, Interrupt,yield, etc.

Thread Basics Series (a) thread creation and startup: Thread creation and startup, join (), daemon thread, callable task.

The main content of this article

    1. What is thread safety?

    2. What is shared mutable variables?

    3. Recognize synchronized keywords

    4. Recognize lock

    5. Synchronized vs Lock


1. What is thread safety

Multi-Threading is a double-edged sword, bringing high efficiency, but also bring security risks. What is thread safety? Controversial once, many versions of the rhetoric. The definition in Java concurrency programming is as follows: When multithreading is accessed, it is always possible to behave correctly. Extended interpretation of "what is correctness". Correctness is that both multithreaded and single-threaded access results in a consistent result. The correctness of a single thread can be described as "what you see is what you know." Use the following example to explain the following.

Sysnexamplev1.java

package com.threadexample.sysn;import java.util.random;import java.util.concurrent.timeunit; public class sysnexamplev1 {   static class task implements   Runnable{        private Integer count=0;         private int cycleSize;         public task (int cyclesize)  {             this.cycleSize=cycleSize;        }          @Override         public void run ()  {            for (int i=0;i<cycleSize ; i++) {                 this.count++;            }        }        private void dosomething () {            final random random =new random ();            try {                timeunit.milliseconds.sleep (Random.nextint (Ten));            } catch  (interruptedexception e)  {                e.printstacktrace ();            }       }        public int getcount () {            return this.count;       }    }     public static void main (String[] args)  throws interruptedexception  {        task task = new task (; )        thread t1=new thread (Task);         thread t2=new thread (Task);         T1.start ();         t2.start ();         t1.join ();         t2.join ();         system.out.println ("Count (number of threads * cycles) =" +task.getcount ());     }}

The Task class maintains an instance variable count as a counter. One count per loop plus 1. Altogether 2 threads are enabled, and each thread loops 1000 times. To ensure that the thread is fully executing the calling thread's join (), the last expected effect: 2*1000=2000.

The test results are as follows (and the results change frequently)

Count (number of threads * cycles) =1958

According to "What You See", 2 threads, 1000 times per loop, of course 2000. But the result is not 2000. Indicates that the task class is not thread-safe.

Simple analysis of the reason: The problem is this.count++, this operation is in line with the operation.

You can easily find the cause by using the Javap-v sysnexamplev1$task.class command that comes with your own code to view bytecode files.

     ...       42: getfield        #3                 &NBSP;&NBSP;&NBSP;//&NBSP;FIELD&NBSP;COUNT:LJAVA/LANG/INTEGER;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;45: &NBSP;ASTORE&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;4&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;47:  aload_3       48: aload_3        49: getfield       #3                    // Field count:Ljava/lang/Integer;        52: invokevirtual  #12                   // method java/lang/integer.intvalue: () I        55: iconst_1       56: iadd        57: invokestatic   #2                    // method java/lang/integer.valueof: (I) ljava/lang/integer;       60: dup_x1        61: putfield       #3                    // Field count:Ljava/lang/Integer; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP, .....

A simple self-increment operation that is broken down into

    1. Gets the value of the current C;

    2. Add 1 to the obtained value;

    3. Write the increment value back to C;

Since it is a composite operation, one thread has updated the data, has not been saved to the shared cache, and another thread reads the data at this time, and there is a case of getting stale data. Under a simple demo, assume that Count C is initialized to 0,

Thread A: Get C;
Thread B: Get C;
Thread A: Adds 1 to the obtained value, and the result is 1;
Thread B: Adds 1 to the obtained value, and the result is 1;
Thread A: The result writes back to C,c is now 1;
Thread B: The result writes back to C,c is now 1;

According to the normal understanding, B should be written back to 2 is correct.

Then how to solve this problem. It's actually very simple. is to deal with synchronized. Before introducing synchronized, let's briefly talk about shared variables.

2. What is shared mutable variables

To write thread-safe code, the core is on the management of State access operations, especially access to shared and mutable states. "Sharing" means that multiple threads can be accessed concurrently, and "mutable" means that the value of a variable can change over its lifetime. Introduce several variables according to different classification

Local variables

Local variables are stored in the thread's own stack. In other words, local variables are never shared by multiple threads. Therefore, the local variables of the underlying type are thread-safe. Here is an example of a local variable of the underlying type:

public void SomeMethod () {Long threadsafeint = 0; threadsafeint++;}
Local Object References

The local reference to the object is not the same as the local variable of the underlying type. Although the reference itself is not shared, the reference refers to an object that is not stored in the stack of threads. All objects are present in the shared heap. So there is the phenomenon of variable escaping. For the knowledge of escaping, you can refer to the "Java Concurrent programming Combat" section 3.2, "Release and Escape".

public void SomeMethod () {Localobject localobject = new Localobject ();  Localobject.callmethod (); METHOD2 (localobject);} public void Method2 (Localobject localobject) {localobject.setvalue ("value");}

The Localobject object in the sample is not returned by the method, nor is it passed to an object outside the SomeMethod () method. Each thread that executes SomeMethod () creates its own Localobject object and assigns a value to the Localobject reference. Therefore, the localobject here are thread-safe. In fact, the entire somemethod () is thread-safe. Even if you pass localobject as an argument to another method of the same class or to a method of another class, it is still thread-safe. Of course, if Localobject is passed on to other threads through certain methods, it is no longer thread-safe.

Object Members

Object members are stored on the heap. If two threads update the same member of the same object at the same time, the code is not thread-safe. Here is a sample:

public class notthreadsafe{StringBuilder builder = new StringBuilder ();    Public Add (String text) {this.builder.append (text); }}

If two threads invoke the NotThreadSafe Add () method on the same instance at the same time, there will be a race condition problem. This is when multithreaded access to object idiom variables, threads are not thread-safe, so you need to use the lock mechanism provided by Java to protect. There are two kinds of locking mechanisms in Java: The synchronized and Lock,lock interfaces and their implementation classes are JDK5 additions, and the author is the famous concurrency expert Doug Lea. This article does not compare synchronized with lock which is inferior.

3. Recognize synchronized Keywords

synchronized is a key word for Java. Java provides 2 synchronization mechanisms, synchronization methods, and synchronization blocks. Synchronization blocks to associate a protected object, the synchronization method is associated with the This object. A code block that is protected by synchronization, allowing only one thread to enter at a time, and how to implement synchronized on the bottom of the JVM.

The synchronization mechanism is built on the inside of an entity called an internal lock or a monitoring lock. (commonly referred to as a monitor in the Java API specification.) The internal lock plays two roles in the synchronization mechanism: exclusive access to an object, and the establishment of a happens-before relationship, which is the key to the visibility problem.

Each object has an internal lock associated with it. Typically, when a thread needs exclusive access to an object's domain, it first needs to request an internal lock on that object, releasing an internal lock when the access ends. During the time the thread obtains the internal lock to release the internal lock, we say that it has this internal lock. Then when a thread has an internal lock, other threads will not be able to get the internal lock. Other threads will be blocked if they attempt to obtain the internal lock.

When a thread releases an internal lock, the Happens-before relationship is established between the operation and subsequent requests to the lock.

For more explanation of the principle, you can refer to one of the deep JVM lock mechanisms: Synchronized and related Java memory model knowledge.

    1. Using the Synchronized Block protection method

      Code block 1.1

public void Run () {synchronized (this) {for (int i=0;i<cyclesize;i++) {this.count++; }    }}

Or

Code block 1.2

public void Run () {-(int i=0;i<cyclesize;i++) {synchronized (this) {this.count++; }        }    }

The difference between the two methods is that the protection range of the synchronized block is different, the result is the same, the former protection range is larger, but the context switch is less; the latter is the opposite. Specifically which form is better, specifically to protect the code block logic.

2. Declare the method with synchronized

Code block 2.1

Public synchronized void Run () {for (int i=0;i<cyclesize;i++) {this.count++; }    }

In this way, the effect of the protection is the same as the code block 1.1.

3. Protection at the class level synchronized

Code block 3.1

public void Run () {synchronized (Sysnexamplev2.class) {for (int i = 0; i < cyclesize; i++) {th        is.count++; }    }}

This approach is the worst of the 4. Because it has the highest protection range and the worst concurrency. This scenario is not suitable for this type of situation. Class-level locking is generally used in single-case mode (double-check lock). In a word, to determine the reasonable size of a synchronized block of code requires a tradeoff between various design requirements, including security, simplicity, and performance.

Synchronized cannot decorate constructors.

4. Recognize lock

Unlike synchronized, you create a lock manually, release the lock, and get the lock. As follows

Lock lock = new Reentrantlock (); Lock.lock (); Critical section lock.unlock ();

Sysnexamplev3.java, which shows the use of lock.

package com.threadexample.sysn;import java.util.random;import java.util.concurrent.timeunit; import java.util.concurrent.locks.lock;import java.util.concurrent.locks.reentrantlock;public  class sysnexamplev3 {   static class task implements   Runnable{       private final lock lock = new  reentrantlock ();        private integer count=0;         private int cycleSize;         public   task (int cyclesize)  {             this.cycleSize=cycleSize;        }          @Override         public  void run () &NBSP;{&NBSp;           for (int i=0;i<cyclesize;i++) {                 try {                      if (Lock.trylock (10, timeunit.seconds)) {                         this.count++;                      }                }  catch  (interruptedexception e)  {                     e.printstacktrace ();                 }finally {                     lock.unlock ();                 }             }        }         //General implementation of this         /*                 public void run ()  {                      for (int i=0;i<cyclesize;i++) {                         lock.lock ();  //  Block until condition holds                         try {                              this.count++;                         } finally {                              lock.unlock ();                         }                     }                 }*/        Public int getcount () {           return  This.count;       }    }    public  static void main (String[] args)  throws InterruptedException {         task task = new task (;    )     task task2 = new task (;      )   thread t1=new thread (Task);        thread  T2=new thread (Task);         t1.start ();         t2.start ();         t1.join ();       &nbSp; t2.join ();         system.out.println ("Count (number of threads * cycles) =" + Task.getcount ());     }}

Locks, like synchronized synchronous blocks, are a thread synchronization mechanism, but more complex than the synchronized synchronization blocks in Java. Java provides the following locks.

650) this.width=650; "src=" Http://s4.51cto.com/wyfs02/M01/83/68/wKioL1dyir_SgPB7AAAqpA5U0VI992.png "title=" 1111. PNG "alt=" Wkiol1dyir_sgpb7aaaqpa5u0vi992.png "/>

The difference and principle of these kinds of locks, this article does not do in-depth discussion.

5.synchronized vs Lock

    1. Synchronized Sync block does not provide timeout function, Lock provides timeout function, use Lock.trylock (long timeout, timeunit timeunit)

    2. Synchronized synchronization block, the use of simple and fast, which also caused its abuse. Can be used with wait (), notify (). Lock belongs to part of the Juc.

    3. Synchronized caused by thread blocking, can be dump, and lock caused by thread blocking cannot dump.

    4. Synchronized is the code that is hosted for the JVM, and Lock is a Java-written control lock. In Java1.5, synchronize is inefficient in performance. Because this is a heavyweight operation, it is necessary to invoke the operating interface, resulting in a possible lock-up that consumes more system time than a lock-out operation. In contrast, using the lock object provided by Java provides a higher performance. But in the Java1.6, there was a change. The synchronize is semantically clear and can be optimized for many optimizations, such as adaptive spin, lock removal, lock coarsening, lightweight locks, bias locks, and more. resulting in synchronize performance on Java1.6 is no worse than lock. Officials also say they are more supportive of synchronize, and there is room for optimization in future releases.

    5. Lock has a fair lock, non-fair lock points. Synchronized only unfair

    6. Synchronized is the CPU pessimistic locking mechanism, that is, the thread obtains the exclusive lock, Lock uses the optimistic locking method. The so-called optimistic lock is that each time without locking but assuming that there is no conflict to complete an operation, if the conflict failed to retry until successful. The mechanism for optimistic locking is the CAS operation (Compare and Swap).

    7. Lock provides additional Conditon

Resources


http://ifeve.com/synchronization/

http://ifeve.com/locks/

http://blog.csdn.net/natian306/article/details/18504111


This article is from a "simple" blog, so be sure to keep this source http://dba10g.blog.51cto.com/764602/1793815

Thread Basics Series (iii) synchronization of threads

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.