Java Concurrent Programming Series 16: Lock lock

Source: Internet
Author: User
Tags dateformat

Lock Lock Introduction

Lock lock Mechanism is a new locking mechanism after JDK 5, unlike the built-in lock, the lock lock must be explicitly declared and the lock is released in the appropriate location. Lock is an interface that is implemented by three specific implementations: Reentrantlock, Reetrantreadwritelock.readlock, and Reetrantreadwritelock.writelock, which are re-entry locks, read locks, and write locks. The lock mechanism is added primarily because there are some functional limitations to the built-in lock. For example, you cannot interrupt a thread that is waiting to acquire a lock and cannot wait indefinitely while waiting for a lock. The built-in lock must be released in the code block that releases the lock, although it simplifies the use of the lock, but it causes other threads that are waiting to acquire the lock to rely on blocking waits to acquire the lock, which means that the built-in lock is actually a blocking lock. The new lock lock mechanism is a non-blocking lock (which is described in more detail later).

First we look at the source of the lock interface:

 Public  interface Lock {    //Unconditional acquisition of Locks    voidLock ();//Get a lock that responds to interrupts    //Can respond to interrupts when acquiring a lock, throws an interrupt exception when interrupted    voidLockinterruptibly ()throwsInterruptedexception;//Polling lock. If you can't get a lock, you're constantly trying to get a lock by polling    BooleanTrylock ();//Timing lock. If a lock cannot be obtained, the lock is tried again every unit of time    BooleanTrylock (LongTime, Timeunit unit)throwsInterruptedexception;//Release get lock    voidUnlock ();//Gets the condition variable of the bound lock instance. Waiting for a condition variable to be satisfied    before//, the lock instance must be held by the current thread. Call the await method of condition    //will automatically release locks held by the current threadCondition newcondition ();

The comments are written in detail, and you can see that the lock lock mechanism adds a responsive interrupt lock and the use of a fair lock is not a built-in lock mechanism lock. The sample code for using the lock lock is as follows:

locknew ReentrantLock();        lock.lock();        try {            //更新对象状态            //如果有异常则捕获异常            //必要时恢复不变性条件            //如果由return语句必须放在这里        }finally {            lock.unlock();        }


Comparison of implementation strategies between Reentrantlock and synchronized

The previous article mentions that synchronized uses a mutex mechanism, and the biggest problem with this synchronization mechanism is that when multiple threads need to acquire a lock, they can only wait for the thread that has acquired the lock to automatically release the lock by blocking the synchronization. This process involves thread blocking and thread wake-up, which needs to be done in the operating system switching from the user state to the kernel state. So the problem is that when multiple threads compete for the same lock, it can cause frequent context switching, low efficiency, and high system overhead. This strategy is called pessimistic concurrency policy and is also a concurrency policy used by synchronized.

Reentrantlock uses a more advanced concurrency strategy, since the blocking caused by the mutex can affect the performance of the system, is there a way to synchronize without blocking? The Concurrent Master Doug Lea (also the author of Lock Lock) proposed to obtain the lock in a spin-off manner. Simply put, if you need to obtain a lock without contention, then the success is achieved; if there is contention for the lock, then the use of failure compensation (JDK 5 to the current JDK 8 is using a constant attempt to regain, until successful) to resolve the contention. Since the spin takes place inside the thread, it does not block other threads, that is, non-blocking synchronization is implemented. This strategy, also known as optimistic concurrency based on conflict detection, is also a concurrency policy used by Reentrantlock.

Simple summary of Reentrantlock and synchronized, the former is reflected in the advance of the following points:

    1. A lock that responds to interrupts. When the thread waiting for the lock is not locked for a long time, you can choose not to continue waiting to handle other things, while the synchronized mutex must block wait, cannot be interrupted
    2. A fair lock can be achieved. The so-called fair lock refers to the fact that multiple threads must wait while waiting for a lock to wait for the thread to request a lock, while the non-fairness lock guarantees this, and each thread has the opportunity to acquire a lock. The synchronized lock and the default lock used by Reentrantlock are non-fairness locks, but the Reentrantlock supports a fair lock, and a Boolean variable specified as true in the constructor is a fair lock. In general, however, the performance of using an unfair lock is better than using a fair lock
    3. Each synchronized can only support binding one condition variable, where the condition variable is the condition that the thread performs the wait or notification, while Reentrantlock supports binding multiple condition variables, and by calling Lock.newcondition (), multiple condition variables can be obtained. However, the number of conditional variables to use depends on the specific circumstances.


How to choose between Reentrantlock and synchronized

Consider using Reentrantlock when some of the built-in locks do not meet some advanced features. These advanced features include: Timed, polled, and interruptible lock acquisition operations, fair queues, and non-block lock locks. Otherwise, you should prefer to use synchronized.

This passage is the advice of the concurrent master Brian Goetz. So, let's analyze why it is still advisable to use synchronized if Reentrantlock has so many advantages.

First, the built-in lock is familiar to the developer lock (which is certainly not convincing), and the advantage of the built-in lock is that it avoids the manual release of the lock. If you forget to call unlock at finally when you use Reentrantlock, it is tantamount to burying a time bomb and affecting the execution of other code (not convincing). Second, using the built-in lock dump thread information can help analyze which call frames acquire which locks, and can help detect and identify the thread that has a deadlock. This is something that Reentrantlock can't do (and that's a little convincing). Finally, synchronized will continue to optimize the future, and the current synchronized has been optimized for adaptive, spin, lock-out, lock-up, lightweight and biased locks, and the performance of thread blocking and wake-up is not that big. On the other hand, the performance of Reentrantlock may stop there, and the likelihood of future optimizations is minimal (well, I recognize it). This is mainly due to the synchronized is the JVM's built-in properties, the implementation of synchronized optimization naturally natural (hehe, is a pro-son).

Using an interruptible lock

An example of the use of interruptible locks is as follows:

    locknew ReentrantLock();    ...........    lock.lockInterruptibly();//获取响应中断锁    try {        //更新对象的状态        //捕获异常,必要时恢复到原来的不变性条件        //如果有return语句必须放在这里,原因已经说过了    }finally{        lock.unlock();        //锁必须在finally块中释放    }

Here's a concrete example of how to use interruptible locks:

First we look at the example of using synchronized to synchronize and then try to break

 Packagecom.rhwayfun.concurrency.r0405;ImportJava.text.DateFormat;ImportJava.text.SimpleDateFormat;ImportJava.util.Date;ImportJava.util.concurrent.TimeUnit;/** * Created by Rhwayfun on 16-4-5. * * Public  class syncinterruptdemo {    //Lock Object    Private StaticObject lock =NewObject ();//Date Formatter    Private StaticDateFormat format =NewSimpleDateFormat ("HH:mm:ss");/** * Write Data * *     Public void Write(){synchronized(lock) {System.out.println (Thread.CurrentThread (). GetName () +": Start writing data at"+ Format.format (NewDate ()));LongStart = System.currenttimemillis (); for(;;) {//write data for 15 seconds                if(System.currenttimemillis ()-Start > +* the){ Break; }            }//After 15 seconds to run hereSystem.out.println (Thread.CurrentThread (). GetName () +": Finish writing data at"+ Format.format (NewDate ())); }    }/** * reading data * /     Public void Read(){synchronized(lock) {System.out.println (Thread.CurrentThread (). GetName () +": Start reading data at"+ Format.format (NewDate ())); }    }/** * Execute the thread that writes the data * /    StaticClass Writer implements runnable{PrivateSyncinterruptdemo Syncinterruptdemo; Public Writer(Syncinterruptdemo Syncinterruptdemo) { This. Syncinterruptdemo = Syncinterruptdemo; } Public void Run() {syncinterruptdemo.write (); }    }/** * Execute read Data thread * /    StaticClass Reader implements runnable{PrivateSyncinterruptdemo Syncinterruptdemo; Public Reader(Syncinterruptdemo Syncinterruptdemo) { This. Syncinterruptdemo = Syncinterruptdemo; } Public void Run() {syncinterruptdemo.read (); System.out.println (Thread.CurrentThread (). GetName () +": Finish reading data at"+ Format.format (NewDate ())); }    } Public Static void Main(string[] args)throwsinterruptedexception {Syncinterruptdemo Syncinterruptdemo =NewSyncinterruptdemo (); Thread writer =NewThread (NewWriter (Syncinterruptdemo),"Writer"); Thread reader =NewThread (NewReader (Syncinterruptdemo),"Reader");        Writer.start (); Reader.start ();//Run for 5 seconds and then try to interrupt the read threadTimeUnit.SECONDS.sleep (5); System.out.println (Reader.getname () +": I don ' t want to wait for anymore at"+ Format.format (NewDate ()));//Interrupt Read threadReader.interrupt (); }}

The results of the operation are as follows:

As you can see from the results, try to break it after the read thread has run for 5 seconds and find no result because the write thread needs to run for 15 seconds, sleep5 seconds after 10 seconds (sleep 5 seconds plus 10 is just the 15 seconds of the write thread), the read line friend display the interrupted information, This also validates the discussion of synchronized, which means that the write thread releases the lock before responding to the interrupt event of the main thread, which means that it is not allowed to be interrupted during the synchronized code block.

Then we use Reentrantlock to try, read the thread can normally respond to interrupts, according to the analysis, after the read thread runs for 5 seconds, the main thread interrupts the read thread when the read thread should be able to properly respond to the interrupt, and then stop the execution of the read data operation. Let's look at the code:

 Packagecom.rhwayfun.concurrency.r0405;ImportJava.text.DateFormat;ImportJava.text.SimpleDateFormat;ImportJava.util.Date;ImportJava.util.concurrent.TimeUnit;ImportJava.util.concurrent.locks.Lock;ImportJava.util.concurrent.locks.ReentrantLock;/** * Created by Rhwayfun on 16-4-5. * * Public  class lockinterruptdemo {    //Lock Object    Private StaticLock lock =NewReentrantlock ();//Date Formatter    Private StaticDateFormat format =NewSimpleDateFormat ("HH:mm:ss");/** * Write Data * *     Public void Write() {lock.lock ();Try{System.out.println (Thread.CurrentThread (). GetName () +": Start writing data at"+ Format.format (NewDate ()));LongStart = System.currenttimemillis (); for(;;) {if(System.currenttimemillis ()-Start > +* the){ Break; }} System.out.println (Thread.CurrentThread (). GetName () +": Finish writing data at"+ Format.format (NewDate ())); }finally{Lock.unlock (); }    }/** * reading data * /     Public void Read()throwsinterruptedexception {lock.lockinterruptibly ();Try{System.out.println (Thread.CurrentThread (). GetName () +": Start reading data at"+ Format.format (NewDate ())); }finally{Lock.unlock (); }    }/** * Execute the thread that writes the data * /    StaticClass Writer implements Runnable {PrivateLockinterruptdemo Lockinterruptdemo; Public Writer(Lockinterruptdemo Lockinterruptdemo) { This. Lockinterruptdemo = Lockinterruptdemo; } Public void Run() {lockinterruptdemo.write (); }    }/** * Execute read Data thread * /    StaticClass Reader implements Runnable {PrivateLockinterruptdemo Lockinterruptdemo; Public Reader(Lockinterruptdemo Lockinterruptdemo) { This. Lockinterruptdemo = Lockinterruptdemo; } Public void Run() {Try{Lockinterruptdemo.read (); System.out.println (Thread.CurrentThread (). GetName () +": Finish reading data at"+ Format.format (NewDate ())); }Catch(Interruptedexception e) {System.out.println (Thread.CurrentThread (). GetName () +": Interrupt reading data at"+ Format.format (NewDate ())); } System.out.println (Thread.CurrentThread (). GetName () +": End reading data at"+ Format.format (NewDate ())); }    } Public Static void Main(string[] args)throwsinterruptedexception {Lockinterruptdemo Lockinterruptdemo =NewLockinterruptdemo (); Thread writer =NewThread (NewWriter (Lockinterruptdemo),"Writer"); Thread reader =NewThread (NewReader (Lockinterruptdemo),"Reader");        Writer.start (); Reader.start ();//Run for 5 seconds and then try to interruptTimeUnit.SECONDS.sleep (5); System.out.println (Reader.getname () +": I don ' t want to wait for anymore at"+ Format.format (NewDate ()));//Interrupt Read threadReader.interrupt (); }}

The results of the operation are as follows:

Obviously, the read thread normally responds to our interrupts, because the read thread outputs the interrupt information, even after the write thread finishes writing the data, and the read thread does not have the information to end the read data, as we expected. This also verifies the analysis of interruptible locks.

Java Concurrent Programming Series 16: Lock lock

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.