Java Multithreading Synchronization (Lock) Implementation method (synchronised and Reentrantlock) __java

Source: Internet
Author: User
Tags mutex

Synchronised

Synchronized is a keyword in Java and is a synchronous lock. It modifies objects in the following ways:

1. Modifies a code block, the decorated code block is called the synchronized statement block, its function scope is the curly braces {} Enclose the code, the function object is calls this code block the object;
2. Modifies a method, the modified method is called the synchronization method, its function scope is the whole method, the function object is invokes this method the object;
3. Modify a static method, the scope of which is the entire static method, the role of the object is all objects of this class;
4. Modify a class, which is scoped to the part of the synchronized followed by parentheses, and the object of the action is all objects of this class. To decorate a block of code

1. when a thread accesses a synchronized (this) synchronization code block in an object, other threads that attempt to access the object are blocked. Let's look at one of the following examples:

"Demo1": The Use of synchronized:

/**
 * Sync thread
/class Syncthread implements Runnable {
    private static int count;

    Public Syncthread () {
        count = 0;
    }

    The public void  run () {
        synchronized (.) {for
            (int i = 0; i < 5 i++) {
                try {
                    System.out.println ( Thread.CurrentThread (). GetName () + ":" + (count++));
                    Thread.Sleep (MB);
                catch (Interruptedexception e) {
                    e.printstacktrace ();

    }}} public int GetCount () {return
        count;
    }
}

Syncthread's Call:

Syncthread syncthread = new Syncthread ();
Thread thread1 = new Thread (syncthread, "SyncThread1");
Thread thread2 = new Thread (syncthread, "SyncThread2");
Thread1.start ();
Thread2.start ();

The results are as follows:

syncthread1:0
syncthread1:1
syncthread1:2
syncthread1:3
syncthread1:4
syncthread2:5 Syncthread2:6
syncthread2:7
syncthread2:8
syncthread2:9

When two concurrent threads (THREAD1 and Thread2) access the synchronized code block in the same object (Syncthread), only one thread can be executed at the same time and another thread is blocked. You must wait until the current thread finishes executing the code block before executing the code block. Thread1 and Thread2 are mutually exclusive because the current object is locked when the code block is executed, and only after the code block is executed can the object lock be released and the next thread can execute and lock the object.

Let's change the syncthread call a little bit:

Thread thread1 = new Thread (new Syncthread (), "SyncThread1");
Thread thread2 = new Thread (new Syncthread (), "SyncThread2");
Thread1.start ();
Thread2.start ();

The results are as follows:

syncthread1:0
syncthread2:1
syncthread1:2
syncthread2:3
syncthread1:4
syncthread2:5
Syncthread2:6
Syncthread1:7
syncthread1:8
syncthread2:9

Not that one thread is blocking the other when it executes a synchronized code block. Why in the above example Thread1 and thread2 are simultaneously executing. This is because synchronized only locks objects, and each object has only one lock (lock) associated with it, and the code above is equivalent to the following code:

Syncthread syncThread1 = new Syncthread ();
Syncthread syncThread2 = new Syncthread ();
Thread thread1 = new Thread (syncThread1, "SyncThread1");
Thread thread2 = new Thread (syncThread2, "SyncThread2");
Thread1.start ();
Thread2.start ();

At this point, two Syncthread objects SyncThread1 and syncThread2 are created, and thread Thread1 executes SYNCTHREAD1 code (run) in the Synchronized object. The thread thread2 executes the synchronized code (run) in the SyncThread2 object, and we know that synchronized locks the object, and there are two locks that lock the SyncThread1 object and the SyncThread2 object separately , and the two locks are mutually exclusive and do not form a mutex, so two threads can execute simultaneously.

2. When a thread accesses a synchronized (this) synchronized code block of an object, another thread can still access a synchronized (this) synchronization code block in that object.

"Demo2": Multiple threads accessing synchronized and non-synchronized code blocks

Class Counter implements runnable{private int count;
    Public Counter () {count = 0;
                public void Countadd () {synchronized (.) {for (int i = 0; i < 5; i + +) {
                    try {System.out.println (Thread.CurrentThread (). GetName () + ":" + (count++));
                Thread.Sleep (100);
                catch (Interruptedexception e) {e.printstacktrace ();
        }}//synchronized code block, the count is not read and write, so you can use the synchronized public void PrintCount () { for (int i = 0; I < 5 i + +) {try {System.out.println (Thread.CurrentThread (). Getnam
                E () + "Count:" + count);
            Thread.Sleep (100);
            catch (Interruptedexception e) {e.printstacktrace ();
        }} public void Run () {String threadname = Thread.CurrentThread (). GetName (); if (ThreadnamE.equals ("A")) {Countadd ();
        else if (threadname.equals ("B")) {PrintCount (); }
    }
}

Calling code:

Counter Counter = new Counter ();
Thread thread1 = new Thread (counter, "A");
Thread thread2 = new Thread (counter, "B");
Thread1.start ();
Thread2.start ();

The results are as follows:

a:0
b count:1
a:1
b count:2
a:2
b count:3
a:3
b count:4
a:4
b count:5

The Countadd in the code above is a synchronized, PrintCount is synchronized. From the results above you can see that when a thread accesses an object's synchronized code block, other threads can access the object's synchronized code block without blocking.

3. Specify that you want to lock an object:

* * * Bank Account Type/class Accounts {String name;

    float amount;
        Public account (String name, float amount) {this.name = name;
    This.amount = amount;
        }//Save money public void deposit (float amt) {amount = AMT;
        try {thread.sleep (100);
        catch (Interruptedexception e) {e.printstacktrace ();
        }///Take money public void withdraw (float amt) {amount-= Amt;
        try {thread.sleep (100);
        catch (Interruptedexception e) {e.printstacktrace ();
    } public float GetBalance () {return amount;
    }/** * Account Operation class * * Accountoperator implements runnable{private accounts;
    public Accountoperator [Account Account] {this.account = account;
            public void Run () {synchronized () {account.deposit (500);
            Account.withdraw (500); System.out.println (Thread.currEntthread (). GetName () + ":" + account.getbalance ()); }
    }
}

Calling code:

Account Account = new Account ("Zhang San", 10000.0f);
Accountoperator accountoperator = new Accountoperator (account);

Final int thread_num = 5;
Thread threads[] = new Thread[thread_num];
for (int i = 0; i < thread_num i + +) {
        threads[i] = new Thread (accountoperator, "thread" + i);
        Threads[i].start ();
}
Run Result:
thread0:10000.0
thread1:10000.0
thread2:10000.0
thread3:10000.0
thread4:10000.0
thread5:10000.0

In the Run method in the Accountoperator class, we add a lock to the account object with synchronized. At this point, when a thread accesses the account object, other threads that attempt to access the account object will block until the thread accesses the end of the account object. That means whoever gets the lock can run the code it controls.
When you have an explicit object as a lock, you can write the program in a manner similar to the following.

public void method3 (Someobject obj)
{
    //obj locked object
    synchronized (obj)
    {
        //Todo
    }
}

When there is no explicit object as a lock, and just want to synchronize a piece of code, you can create a special object to act as a lock:

Lass Test implements Runnable
{
    private byte[] lock = new Byte[0];  Special instance variable public
    void method ()
    {
        synchronized (lock) {
            //Todo Sync code block
        }
    }

    Public void Run () {

    }
}

Description: 0-Length byte array objects are more economical to create than any object--view compiled bytecode: A 0-length byte[] object takes only 3 opcode, while object lock = new Object () requires a 7-line opcode. Modify a method

Synchronized it is simple to modify a method by adding synchronized,public synchronized void method () {//todo} to the front. The synchronized cosmetic method is similar to decorating a code block, except that the cosmetic code block is a range of braces enclosed, while the cosmetic method scope is the entire function. If you change the Run method in "Demo1" to the following way, you will achieve the same effect.

"Demo4": Synchronized modifies a method

Public synchronized void Run () {to
    (int i = 0; i < 5; i + +) {
        try {
            System.out.println (thread.currentthre AD (). GetName () + ":" + (count++);
            Thread.Sleep (MB);
        catch (Interruptedexception e) {
            e.printstacktrace ();}}}

The synchronized acts on the whole method.
Writing a:

Public synchronized void Method ()
{
    //Todo
}

Writing two:

public void Method ()
{
    synchronized (this) {
        //Todo
    }
}}

Writing a modified is a method, writing two modified is a code block, but the writing one and the second is equivalent, are locked in the whole method of content.

Note the following points when using synchronized to decorate a method:

The 1.synchronized keyword cannot be inherited.

Although you can use synchronized to define a method, synchronized is not part of the method definition, so the Synchronized keyword cannot be inherited. If a method in a parent class uses the Synchronized keyword and overrides the method in a subclass, the method in the subclass is not synchronized by default, and it must be explicitly added to this method of the subclass synchronized keyword. Of course, the corresponding method in the parent class can also be called in the subclass method, so that although the method in the subclass is not synchronized, the subclass invokes the synchronization method of the parent class, so the method of the subclass is equivalent to synchronization. The example code for both of these approaches is as follows:

Add the Synchronized keyword to the subclass method

Class Parent {public
    synchronized void Method () {}
}
class Child extends Parent {public
    synchronized VO Id method () {}
}

To invoke the synchronization method of the parent class in a subclass method

Class Parent {public
    synchronized void method () {   }
}
class Child extends Parent {public
    void method () {Super.method ();   }

2. You cannot use the Synchronized keyword when defining an interface method.

3. The constructor method cannot use the Synchronized keyword, but can be synchronized using a synchronized code block. To modify a static method

Synchronized can also modify a static method, as follows:

Public synchronized static void method () {
    //Todo
}

We know that static methods belong to the class and not to the object. Similarly, the synchronized-modified static method locks all objects of this class. We have made some changes to Demo1 as follows:

"Demo5": Synchronized modified static method

* *
 sync thread
/class Syncthread implements Runnable {
    private static int count;

    Public Syncthread () {
        count = 0;
    }

    Public synchronized static void method () {for
        (int i = 0; i < 5; i + +) {
            try {
                System.out.println (threa D.currentthread (). GetName () + ":" + (count++));
                Thread.Sleep (MB);
            catch (Interruptedexception e) {
                e.printstacktrace ();

    }}} Public synchronized void Run () {method
        ();
    }
}

Calling code:

Syncthread syncThread1 = new Syncthread ();
Syncthread syncThread2 = new Syncthread ();
Thread thread1 = new Thread (syncThread1, "SyncThread1");
Thread thread2 = new Thread (syncThread2, "SyncThread2");
Thread1.start ();
Thread2.start ();

The results are as follows:

syncthread1:0
syncthread1:1
syncthread1:2
syncthread1:3
syncthread1:4
syncthread2:5 Syncthread2:6
syncthread2:7
syncthread2:8
syncthread2:9

SyncThread1 and SyncThread2 are two objects of syncthread, but are synchronized while Thread1 and Thread2 concurrently execute. This is because static method methods are invoked in run and static methods are class, so syncThread1 and syncThread2 are equivalent to using the same lock. This is different from the Demo1. Modify a class

Synchronized can also be used as a class, using the following:

Class ClassName {public
    void method () {
        synchronized (classname.class) {
            //Todo
        }
}}

We'll make some changes to the DEMO5.
"Demo6": Modifying a class

/**
 * Sync thread
/class Syncthread implements Runnable {
    private static int count;

    Public Syncthread () {
        count = 0;
    }

    public static void Method () {
        synchronized (syncthread.class) {for
            (int i = 0; i < 5; i + +) {
                try {
                    System.out.println (Thread.CurrentThread (). GetName () + ":" + (count++));
                    Thread.Sleep (MB);
                catch (Interruptedexception e) {
                    e.printstacktrace ();

    }}} Public synchronized void Run () {method
        ();
    }
}

The effect is the same as "Demo4", where the synchronized for a class T is to lock the class T, and all objects of T are in the same lock.

Summary:

A. Whether the Synchronized keyword is added to the method or the object, if the object it acts on is non-static, the lock it obtains is an object, and if the synchronized object is a static method or a class, the lock it obtains is the same lock on the class, all objects of the class.
B. Each object has only one lock (lock) associated with it, and whoever gets the lock can run the piece of code it controls.
C. Synchronization is costly as a result of system overhead, and may even cause deadlocks, so avoid unnecessary synchronization controls as much as possible. Java.util.concurrent.locks.lock class

Lock is an interface under the Java.util.concurrent.locks package, the lock implementation provides a more extensive locking operation than using synchronized methods and statements, and it handles thread synchronization issues in a more elegant way, we take Java Threads (ii) An example of a simple implementation of the same effect as sychronized, the code is as follows:

1.public class locktest {   2.    public static void  main (String[] args)  {   3.        final  Outputter1 output = new outputter1 ();   4.         new thread ()  {   5.             public void run ()  {   6.                 output.output ("Zhangsan");   7.             };   8.         }.start ();         9.         new thread ()  {   10.             public&Nbsp;void run ()  {   11.                 output.output ("Lisi");   12.             };   13.        }.start ();    14.    }   15.}    16.class outputter1 {   17.    private lock lock  = new reentrantlock ();//  lock Object    18.    public void  Output (string name)  {   19.        // todo
  Thread Output Method    20.        lock.lock ();//  get lock    21.        try {   22.             for (int i = 0; i < name.length ()  i++)  {   23.                 system.out.print (Name.charAt (i));   24.             }   25.         } finally {   26.             lock.unlock ();//  release lock    27.         }   28.    }  }

This achieves the same synchronization effect as sychronized, it should be noted that the Sychronized modified method or statement block after the completion of the code lock automatic release, and lock requires us to manually release the lock, so in order to ensure that the lock was eventually released (abnormal situation), To place the mutex in a try, release the lock in the finally. the difference between synchronized and lock

Java.util.concurrent.locks.lock class

· The boundary of the critical zone is flexible.

· The order of the lock release is determined by the user

· can have multiple condition


Reentrantlock class

The lock frame in Java.util.concurrent.lock is an abstraction of the lock, which allows the implementation of the lock as a Java class rather than as a language feature. This leaves space for the various implementations of lock, which may have different scheduling algorithms, performance characteristics, or locking semantics. The Reentrantlock class implements lock, which has the same concurrency and memory semantics as the synchronized, but adds features such as lock voting, timed lock waiting, and interruptible lock waiting. In addition, it provides better performance in the case of intense contention. (In other words, when many threads want to access shared resources, the JVM can spend less time scheduling threads, and more on execution threads.) )

A reentrant lock reentrantlock means that when a thread acquires a lock, it can re-enter the block once the lock has not been released, and the second time it accesses another block of code that locks the lock.

What does the reentrant lock mean? In short, it has a lock-related fetch counter, and if a thread that owns the lock gets the lock again, the fetch counter is added 1, and the lock needs to be released two times to get real release. This mimics the semantics of the synchronized; If a thread enters a synchronized block protected by a monitor already owned by the thread, it allows the thread to proceed, not releasing the lock when the thread exits the second (or subsequent) synchronized block. The lock is released only if the thread exits the first synchronized block it enters into the monitor protection.

In basic usage, the two are similar. But Reentrantlock added some advanced features, as long as the following three:

first, waiting can be interrupted

Second, fair lock

Third, lock binding multiple conditions

Wait interruptible means that the waiting thread can choose to continue waiting for more than a certain amount of time, or you can do something else without waiting. This is useful for synchronized blocks that have a very long execution time.

A fair lock means that a thread must acquire a lock in the order in which it is queued, and not a fair lock does not guarantee it. In an unfair lock, it is possible for any waiting thread to acquire a lock.

A lock binding multiple conditions means that a Reentrantlock object can bind multiple condition objects at the same time. In syncronized, the wait and notify of a lock object, or the Notifyall method, can implement an implied condition that, if associated with more than one condition, additional locks are added. Reentrantlock do not need to add a lock, just multiple calls to the Newcondition () method. the difference between Reentrantlock and synchronized

1, Reentrantlock has synchronized the same concurrency and memory semantics, in addition to lock voting, timed locks, waiting and interrupt lock waiting
Both threads A and B get the lock on object o, assuming that a gets the object o lock and B waits for a to release the lock on O,
If you use synchronized, if A is not released, B will wait forever and cannot be interrupted
If you use Reentrantlock, if A is not released, you can make B wait long enough to interrupt the wait and do something else.

Reentrantlock gets locked with three ways:
A) lock (), if the lock is returned immediately, if another thread holds the lock, the current thread remains dormant until the lock is acquired
b trylock (), returns True if the lock is acquired immediately, and returns False if the other line one thread hold the lock;
c) Trylock (long timeout,timeunit unit), if a lock is acquired immediately returns true, if the other line one thread hold the lock, waits for the parameter given the time, and if the lock is acquired during the wait, returns true if the wait timeout, returns false;
d) lockinterruptibly: If the lock is returned immediately, if the lock is not acquired, the current thread is dormant until or locked, or when the front thread is interrupted by another

2, synchronized is implemented on the JVM level, not only through a number of monitoring tools to monitor synchronized lock, and in the code execution, the JVM will automatically release the lock, but use lock is not, lock is implemented through the code, To ensure that the lock is released, you must place the unlock () in the finally{}

3, in the resource competition is not very intense situation, synchronized performance is better than Reetrantlock, but in the case of intense resource competition, synchronized performance will fall dozens of times times, but Reetrantlock performance can maintain the normal;

Compared with syncronized, reentrantlock performance can be maintained at a relatively stable level. Starting from java1.6, syncronized and Reentrantlock are completely flat in performance. So after 1.6, performance is not the reason to choose Reentrantlock.

Finally, summarize

Many people know that the performance of the reentrant lock is higher than the synchronized, in fact this is stuck in the JDK1.5 phase, in the JDK to 1.6 when the introduction of a number of synchronized optimization measures, such as spin locks, lightweight locks, bias locks, performance on the basic and the lock flat. Personally feel that if you do not use some special features of the lock, try not to use the lock, there are two main reasons:

1, after all, the majority of developers familiar with the synchronized far more than the lock and re-entry lock need to manually release the lock, if once forgotten release is very tragic;

2, synchronized after all is the JVM semantic level, JDK1.6 performance is not weaker than lock, later Ken will be more for this part of the performance optimization.

Reference:

concurrent Programming threadlocal, Volatile, synchronized, atomic keyword literacy

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.