Java lock mechanism

Source: Internet
Author: User
Tags benchmark readable


Multithreading and concurrency are not new to Java, Java encapsulates a thread-related class library, and the core class library contains a thread class that you can use to build, start, and manipulate threads. Of course, Java is more recommended to implement the Runnable method to achieve multi-threading, because he is more easy to use, more readable, and can be reused thread pool to bring higher performance.

The Java language includes constructs--synchronized and volatile that communicate concurrency constraints across threads. While simplifying the development of platform-independent concurrency classes, it never makes it much more tedious to write concurrent classes, but makes it easier.

Multithreaded programming inevitably involves multi-threaded thread synchronization problems. Java provides a variety of ways to handle thread synchronization problems.

1. Synchronized key Words

The Synchronized keyword is one of the most commonly used methods, with a real performance and worst-performing approach, but its readability is strong and still widely used.

Each object in Java can be used as a lock.

For synchronous methods, the lock is the current instance object.

For a static synchronization method, the lock is the class object of the current object.

For synchronous method blocks, the lock is an object configured in synchonized brackets.

The JVM specification specifies that the JVM implements method synchronization and code block synchronization based on entering and exiting the monitor object, but the implementation details are different. Code block synchronization is implemented using Monitorenter and monitorexit directives, and method synchronization is implemented in another way, details are not explained in detail in the JVM specification, but synchronization of methods can also be implemented using these two instructions. The monitorenter instruction is inserted at the beginning of the synchronization code block after compilation, and Monitorexit is inserted at the end of the method and at the exception where the JVM guarantees that each monitorenter must have corresponding monitorexit paired with it. Any object has a monitor associated with it, and when a monitor is held, it is locked. When the thread executes to the monitorenter instruction, it attempts to take ownership of the monitor that corresponds to the object, which is attempting to acquire the lock on the object.

A more common use is the cosmetic method, which enables a method to be mutually exclusive to invoke:

/** * Created by Jpbirdy on15-1-22. */Package Jpbirdy.thread.lock; Import Java.util.concurrent.locks.ReentrantLock; /** * @author Jpbirdy * @project javaalgorithms * @class locktest * @date 15-1-22 13:35 * @desc */public class Synchronize    dlocktest{private int total = 0;        The thread synchronization keyword for the adornment method, which provides method-level lock public synchronized voidadd () throws Interruptedexception {total + +;    Thread.Sleep (1000);     } public int get () {returntotal;}        public static class Innerrunnable implements Runnable {privatesynchronizedlocktest synchronizedlocktest;         private int threadId;  publicinnerrunnable (int threadId, synchronizedlocktest synchronizedlocktest) {this.synchronizedlocktest            = Synchronizedlocktest;        This.threadid =threadid; } public Innerrunnablesetsynchronizedlocktest (Synchronizedlocktest synchronizedlocktest) {THIS.S            Ynchronizedlocktest = Synchronizedlocktest;        return this; }        @Override public void Run () {try {System.out.println (Synchroni               Zedlocktest.get ());            Synchronizedlocktest.add ();            } catch (Interruptedexception e) {e.printstacktrace ();        } System.out.println ("thread" + threadId + "Addover"); }} public static Voidmain (string[] args) throws Exception {synchronizedlocktestsynchronizedlocktest =        New Synchronizedlocktest ();            for (int i=0; i<10; i++) {New Thread (newinnerrunnable (i, Synchronizedlocktest)). Start ();        Thread.Sleep (1); }    }}

Run display

0111111111thread 0add overthread 9add overthread 8add overthread 7add overthread 6add overthread 5add overthread 4add over Thread 3add overthread 2add overthread 1add over

Get is not locked, but the set method adds a lock, so each thread waits for each Add method to execute after the sleep method finishes before it can be re-entered.

In the case of multiple chunks in a method, but only want to compete for a certain part as a critical section, other parts are not wired synchronization problems, you can use the sychronized block implementation:

/** * Created by Jpbirdy On15-1-22. */Package Jpbirdy.thread.lock; /** * @author jialou.jp * @project javaalgorithms * @class locktest * @date 15-1-22 17:12 * @desc */public class Synchroni    zedlocktest{private int total = 0; public int Get () {returntotal;} <pre name= "code" class= "Java" >//Modifier code block thread synchronization keyword, providing block-level lock 
public void Add2 () throwsinterruptedexception {System.out.println (' Out of synchronized '); synchronized (this) {total + + ; Thread.Sleep (1000); }} public static classinnerrunnable implements Runnable {privatesynchronizedlocktest synchronizedlocktest; private int T Hreadid; publicinnerrunnable (int threadId, synchronizedlocktest synchronizedlocktest) {this.synchronizedlocktest = Synchronizedlocktest; This.threadid =threadid; } public innerrunnable Setsynchronizedlocktest (synchronizedlocktestsynchronizedlocktest) { This.synchronizedlocktest = Synchronizedlocktest; return this; } @Override public void Run () {try {//System.out.println (Synchronizedlocktest.get ()); Synchronizedlocktest.add2 ();} CA TCH (interruptedexception e) {e.printstacktrace ();} SYSTEM.OUT.PRINTLN ("thread" + threadId + "add over"); }} public static Voidmain (string[] args) throws Exception {synchronizedlocktestsynchronizedlocktest = new Synchronizedlo Cktest (); for (int i=0; i<10; i++) {new Thread (new InnerrunnaBLE (i,synchronizedlocktest)). Start (); Thread.Sleep (1); } }}



The result is:

Out of Synchronizedout of Synchronizedout of Synchronizedout of Synchronizedout of Synchronizedout of Synchronizedout of S  Ynchronizedout of Synchronizedout of Synchronizedout of Synchronizedthread 0add overthread 9add overthread 8add overthread 7add overthread 6add overthread 5add overthread 4add overthread 3add overthread 2add overthread 1add over

Only add and sleep are in the thread synchronization block.

Of course, in theory sychronized can also modify a class (object name, class name, or this to represent itself) and make an asynchronous call to the class as a whole. This enables the get operation to wait to avoid reading dirty data when a modification operation is in progress (DBMS? In JDBC, if you want to implement the Java layer read-write asynchronous, you can lock the connection object, and in Hibernate, the session object should be locked.


/** * Created by Jpbirdy on15-1-22. */Package Jpbirdy.thread.lock; /** * @author jialou.jp * @project javaalgorithms * @class locktest * @date 15-1-22 13:35 * @desc */public class Objectloc     ktest{private int total = 0; Modifies the thread synchronization keyword for an object, providing a method-level lock of public void Add () throwsinterruptedexception {System.out.println ("in Add" + thread.cu        Rrentthread (). GetId ());            Synchronized (this) {System.out.println ("in Add" + thread.currentthread (). GetId () + "Get the Clock");           Total + +;           Thread.Sleep (1000);        System.out.println ("in Add" + thread.currentthread (). GetId () + "release the Clock"); }} public int get () throwsinterruptedexception {System.out.println (' in Get ' +thread.currentthread (). Get        Id ());        int total = 0;            Synchronized (this) {System.out.println ("in Get" + Thread.CurrentThread (). GetId () + "Get the Clock");//            return total;           Total = This.total; ThrEad.sleep (1000);        System.out.println ("in Get" + Thread.CurrentThread (). GetId () + "release th clock");    } return total;        } public static class Innerrunnableimplements Runnable {private objectlocktestsynchronizedlocktest;         private int threadId; publicinnerrunnable (int threadId, objectlocktest synchronizedlocktest) {this.synchronizedlocktest = Syn            Chronizedlocktest;        This.threadid =threadid; } public Innerrunnablesetsynchronizedlocktest (Objectlocktest synchronizedlocktest) {This.synchro            Nizedlocktest = Synchronizedlocktest;        return this; } @Override public void Run () {try {System.out.println (synchro               Nizedlocktest.get ());            Synchronizedlocktest.add ();            } catch (Interruptedexception e) {e.printstacktrace (); } System.out.println ("Thread" + threadId + "Addover"); }} public static Voidmain (string[] args) throws Exception {objectlocktestsynchronizedlocktest = new Ob        Jectlocktest ();            for (int i=0; i<10; i++) {New Thread (newinnerrunnable (i, Synchronizedlocktest)). Start ();        Thread.Sleep (1); }    }}

The result is:

in get11in get11get the clockin get12in get13in get14in get15in get16in get17in get18in get19in get20in get11release th cl  ock0in get20get the Clockin add11in get20release th clock0in get19get the Clockin add20in get19release th clock0in add19in Get18get the clockin get18release th clock0in add18in get17get the clockin get17release th clock0in add17in get16get the Clockin get16release th clock0in add16in get15get the clockin get15release th clock0in add15in get14get the Clockin get14r Elease th clock0in add14in get13get the clockin get13release th clock0in add13in get12get the clockin get12release th cloc k0in add12in Add13get The Clockin add13release the Clockthread 2add overin add14get the Clockin add14release the Clockthre Ad 3add Overin add15get the Clockin add15release the Clockthread 4add overin add16get the Clockin add16release the clockth Read 5add Overin add17get the Clockin add17release the Clockthread 6add overin add18get the Clockin add18release the clock Thread 7add Overin ADD19Get the Clockin add19release the Clockthread 8add overin add20get the Clockin add20release the Clockthread 9add overin add 11get the Clockin add11release the Clockthread 0add overin add12get the Clockin add12release the Clockthread 1add over


In a thread, get and add are alternately obtained (in fact, in order, which is related to resource contention scheduling) and executed.

It is worth mentioning that sychronized is a JVM-level operation, so regardless of the result of code execution in the synchronization block, the code block execution will inevitably release the lock for the other thread to get execution power.

2, Reentrantlock Lock

After JDK1.5, a code-level lock (Java.util.concurrent.lock) appears, similar to the Metex operation of the operating system. A Reentrantlock object is established in the object, and thread synchronization can be achieved through the Lock.lock () method when resource contention is required.

A class can have more than one Reentrantlock object, to identify multiple 0-bounded resources, and to implement multi-resource multithreaded competitive operations.

/** *created by Jpbirdy on 15-1-22. */Package Jpbirdy.thread.lock; Importjava.util.concurrent.locks.ReentrantLock; /** * @author jialou.jp * @project javaalgorithms * @class reentrantlocktest * @date 15-1-22 14:38 * @desc */public class Reent    rantlocktest{Private Reentrantlock lock = new Reentrantlock ();    private int total = 0;       public void Add () throws Interruptedexception {Lock.lock ();       Total + +;       Thread.Sleep (1000);    Lock.unlock ();        } public static class Innerrunnable implements Runnable {private reentrantlocktest reentrantlocktest;       Public innerrunnable (Reentrantlocktest reentrantlocktest) {this.reentrantlocktest = Reentrantlocktest;           } @Override public void Run () {try {reentrantlocktest.add ();           } catch (Interruptedexception e) {e.printstacktrace ();       } System.out.println ("Add over");    }} public static void Main (string[] args) throws Exception {reentrantlocktest reentrantlocktest = new Reentra       Ntlocktest ();           for (int i=0; i<10; i++) {New Thread (new Innerrunnable (Reentrantlocktest)). Start ();       Thread.Sleep (1); }    }}

The results are as follows:

Add Overadd overadd overadd overadd overadd overadd overadd overadd overadd over


The famous concurrenthashmap is to implement thread synchronization through Reentrantlock.

3. Difference

Flexibility, the flexibility of reentrantlock must be higher. Because the lock is implemented at the code level, it can be released at any time or retrieved.

For example, in a program, when the code executes to a step (such as after a certain initialization is complete), the latter step can temporarily release the lock without worrying, and call the yield method to have the thread re-dispatched. If a system task now needs more threads to get CPU resources, he can also get a lock at this point, otherwise the scheduling of resources is meaningless.

In sychronized, once a thread gets a run (that is, a lock), it will have to consume until the block/method ends, that is, at this point, no matter how the operating system is scheduled, no other thread can get the lock and go to the operation of the method.

But the advantage of sychronized is that it is readable. And actually implemented on the JVM, can be understood as making a lightweight lock control mode. In situations where the task is not very complex, it should be limited by using the Sychronized method to implement thread synchronization. Also mentioned above, sychronized is a mechanism at the JVM level, so the lock is freed regardless of the result of execution in the sychronized block. And Reentrantlock is different, because in fact the code level of the lock, once the code throws an exception, which will cause the entire code block block, the unlock method will not be executed, so in the use of Reentrantlock, It is customary to wrap the contents of the lock below with try-catch-finally and put the unlock method in the finally. Otherwise it is easy to cause a deadlock.

The other thing to pay attention to is efficiency. Here are some quotes:

Compare the scalability of Reentrantlock and synchronized

Tim Peierls uses a simple linear congruent pseudo-random number generator (PRNG) to build a simple evaluation that measures the relative scalability of synchronized and Lock. This example is good because PRNG is actually doing some work every time nextrandom () is called, so the benchmark program is really measuring a reasonable, real synchronized and Lock application, Instead of testing the code purely on paper or doing nothing (just like many so-called benchmark programs.) )

In this benchmark program, there is a pseudorandom interface, which has only one method nextrandom (int bound). This interface is very similar to the functionality of the Java.util.Random class. Since the next random number is generated, PRNG uses the newly generated number as input, and maintains the last generated number as an instance variable, with the emphasis that the code snippet that updates this state is not preempted by other threads, so I'm going to use some sort of lock to ensure that. (The Java.util.Random class can also do this.) We built two implementations for pseudorandom, one using syncronized and the other using Java.util.concurrent.ReentrantLock. The driver generates a number of threads, each of which frantically competes for time slices, and then calculates how many rounds per second the different versions can perform. Figure 1 and Figure 2 summarize the results of the different number of threads. This evaluation is not perfect, and only runs on two systems (one is dual Xeon running Hyper-threading Linux and the other is a single-processor Windows system), but it should be enough to show the scalability benefits of synchronized compared to Reentrantlock.

The graphs in Figure 1 and Figure 2 show throughput rates in units of calls per second and adjust different implementations to 1 thread synchronized. Each implementation is relatively quick to focus on a steady state of throughput, which usually requires the processor to be fully utilized, most of the processor time is spent on the actual work (computer random number), only a small amount of time spent on thread scheduling expenses. You'll notice that the synchronized version behaves quite poorly when dealing with any type of contention, while the Lock version spends a fairly small amount of time on scheduled expenses, leaving space for higher throughput and more efficient CPU utilization.

Comprehensive analysis, Reentrantlock has greater flexibility, and its performance will be higher than sychronized blocks when multiple resources compete for the same lock. The experiment also proves that the execution efficiency of sychronized block will decrease sharply when the thread increases.

In all aspects, Reentrantlock is better than sychronized block, but in the absence of competitive resources, performance does not appear bottleneck when the sychronized block should be preferred, increase the readability of the code. But when we need a freely customizable, can vote to get lock or more flexible lock control, you can not hesitate to choose Reentrantlock to control.

5 times the mantra. Do It best, then fastest!

Java lock mechanism

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.