Java Concurrency Programming: Lock

Source: Internet
Author: User
Tags finally block

This article transferred from: http://www.cnblogs.com/dolphin0520/p/3923167.html

In Java, you can use the Synchronized keyword to implement synchronous access to shared variables between threads. From Java 1.5, there is another way to implement synchronous access--lock under the Java.util.concurrent.locks package.

Synchronized defects If a code block is synchronized decorated, when a thread acquires the corresponding lock and executes the block, the other thread waits until the thread that acquires the lock releases the lock, and the thread that has acquired the lock releases the lock in only two cases: 1)    The thread that acquires the lock executes the code block, and then the thread releases the possession of the lock, and 2) the thread executes an exception, and the JVM causes the thread to automatically release the lock.    So if the thread that acquires the lock is blocked by waiting for IO or other reasons (such as calling the Sleep method), but the lock is not released, the other threads can only wait, which is very much the intention of the program to execute efficiently.    Therefore, a mechanism is needed to allow waiting threads to wait indefinitely (for example, to wait for a certain amount of time or to respond to interrupts), which can be done with lock. Another example: when there are multiple threads reading and writing files, there is a conflict between read and write operations, and write operations and writes conflict, but there is no conflict between read and read operations. If you use the Synchronized keyword for synchronization, it can cause a problem: If multiple threads are just reading, when a thread is reading,Other threads can only wait for a read operation。 Therefore, a mechanism is needed to enable multiple threads to simply read, and there will be no conflicts between threads, which can be done with lock.    In addition, the lock can be used to know that the line threads has not been successfully acquired, and synchronized is not able to do so. To summarize, that is, lock provides more functionality than synchronized. However, note the following two points: 1) lock is not built into the Java language, synchronized is a Java language keyword and is therefore built-in. Lock is a class that can be accessed synchronously by this class, 2) synchronized does not require the user to manually release the lock, when the synchronized method or synchronized code block is executed, the system will automatically let the field release the use of the lock While lock must have the user manually release the lock, it is possible to cause a deadlock if the lock is not actively released. Second, the java.util.concurrent.locks under the common class 1.LockLock is an interface:
Public interface Lock {    void lock ();    void Lockinterruptibly () throws interruptedexception;    Boolean trylock ();    Boolean Trylock (long time, Timeunit unit) throws interruptedexception;    void unlock ();    Condition newcondition ();}
The following describes the use of each method in the lock interface individually, lock (), Trylock (), Trylock (long time, Timeunit unit), and lockinterruptibly () are used to acquire the lock. The UnLock () method is used to release the lock. Newcondition () This method is not described here for the moment, and will be described in the following thread collaboration article.
Four methods are declared in lock to acquire a lock, so what is the difference between the four methods?
First, the lock () method is the most commonly used method, which is used to acquire a lock. Waits if the lock has been fetched by another thread.
As mentioned earlier, if you use lock, you must voluntarily release the lock, and the lock will not be released automatically when an exception occurs. Therefore, in general, the use of lock must be done in the try{}catch{} block, and the operation to release the lock is placed in the finally block to ensure that the lock must be released to prevent the occurrence of deadlocks. The use of lock for synchronization is usually done in the following form:
Lock lock = ...; Lock.lock (); try{    //Processing Task}catch (Exception ex) {     }finally{    lock.unlock ();   Release Lock}

The Trylock () method is a return value that represents the attempt to acquire a lock, returns true if it succeeds, or false if the fetch fails (that is, the lock has been fetched by another thread), which means that the method returns immediately anyway. You won't be waiting there until you get the lock.
The Trylock (long time, Timeunit unit) method and the Trylock () method are similar except that the method waits for a certain amount of time when the lock is not reached, and returns False if the lock is not held within the duration of the period. Returns true if the lock was obtained at the beginning or if the lock was obtained during the wait period. So, in general, the use of trylock to acquire locks is as follows:
Lock lock = ...; if (Lock.trylock ()) {    lock.lock ();     try{         //Processing Task     }catch (Exception ex) {              }finally{         lock.unlock ();   Release lock     }  }else {    //If the lock cannot be acquired, do other things directly}

The lockinterruptibly () method is special, and when the lock is acquired by this method, if the thread is waiting to acquire the lock, the thread can respond to the interrupt, that is, the wait state of the break thread. It is also said that when two threads pass through lock.lockinterruptibly () to acquire a lock, if thread A acquires a lock at this point, and thread B is only waiting, then the call to thread B of the Threadb.interrupt () method can be used in the wait process of break thread B.
Because an exception was thrown in the declaration of Lockinterruptibly (), lock.lockinterruptibly () must be placed in a try block or in a call to lockinterruptibly () Out-of-method declarations throw interruptedexception. Lockinterruptibly () is therefore generally used in the following form:
public void Method () throws Interruptedexception {    lock.lockinterruptibly ();    try {        //...    }    finally {        lock.unlock ();    }   }

Note that when a thread acquires a lock, it is not interrupted by the interrupt () method. Because itself in the previous article, the separate call to the interrupt () method does not break the thread in the running process, only the threads in the blocking process can be interrupted.
Therefore, when a lock is acquired through the lockinterruptibly () method, it can be interrupted if it cannot be obtained and only waits.
   and with synchronized modification, when a thread waits for a lock, it cannot be interrupted, only waiting.

2.ReentrantLock
Reentrantlock, which means "reentrant lock", describes the concept of reentrant locking in the next section. Reentrantlock is the only class that implements the lock interface, and Reentrantlock provides more methods. Here are some examples to see how to use Reentrantlock.
Example 1,lock () the correct way to use
public class Test {private arraylist<integer> ArrayList = new arraylist<integer> ();                 public static void Main (string[] args) {final Test test = new test ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };                 }.start ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };    }.start ();    public void Insert (thread thread) {Lock lock = new Reentrantlock ();        Note this place Lock.lock ();            try {System.out.println (Thread.getname () + "got Lock");            for (int i=0;i<5;i++) {arraylist.add (i); }} catch (Exception e) {//Todo:handle Exception}finally {System.out.println (thre            Ad.getname () + "release lock");        Lock.unlock (); }    }}

The output results are as follows:
Thread-0 got the lock Thread-1 got the lock Thread-0 released the lock Thread-1 released the lock

Maybe some friends will ask, how will output this result? How does a second thread get a lock before the first thread releases the lock? The reason is that the lock variable in the Insert method is a local variable, and each thread will save a copy when executing the method, so it is natural that each thread executes to lock.lock () to obtain a different lock, so there is no conflict.
It's easier to know why it's changed, just declare lock as a property of the class.
public class Test {private arraylist<integer> ArrayList = new arraylist<integer> ();    Private lock lock = new Reentrantlock ();                 Note This place public static void main (string[] args) {final Test test = new test ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };                 }.start ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };    }.start ();        public void Insert (thread thread) {lock.lock ();            try {System.out.println (Thread.getname () + "got Lock");            for (int i=0;i<5;i++) {arraylist.add (i); }} catch (Exception e) {//Todo:handle Exception}finally {System.out.println (thre            Ad.getname () + "release lock");        Lock.unlock (); }    }}
This is the correct way to use lock.

Example 2,trylock () method of Use
public class Test {private arraylist<integer> ArrayList = new arraylist<integer> ();    Private lock lock = new Reentrantlock ();                 Note This place public static void main (string[] args) {final Test test = new test ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };                 }.start ();            New Thread () {public void run () {Test.insert (Thread.CurrentThread ());        };    }.start (); public void Insert (thread thread) {if (Lock.trylock ()) {try {SYSTEM.OUT.PR                Intln (Thread.getname () + "Got the Lock");                for (int i=0;i<5;i++) {arraylist.add (i); }} catch (Exception e) {//Todo:handle Exception}finally {System.                Out.println (Thread.getname () + "release lock");            Lock.unlock ();    }} else {        System.out.println (Thread.getname () + "Get lock Failed"); }    }}

Output Result:
Thread-0 got lock Thread-1 get lock failed Thread-0 release lock

Example 3,lockinterruptibly () How to use a response interrupt:
public class Test {private lock lock = new Reentrantlock ();        public static void Main (string[] args) {test test = new test ();        MyThread thread1 = new MyThread (test);        MyThread thread2 = new MyThread (test);        Thread1.start ();                 Thread2.start ();        try {thread.sleep (2000);        } catch (Interruptedexception e) {e.printstacktrace ();    } thread2.interrupt ();   public void Insert (thread thread) throws interruptedexception{lock.lockinterruptibly (); Note that if you need to properly interrupt the thread that waits for the lock, you must place the fetch lock outside and then throw interruptedexception the try {System.out.println (Thread.getname () + "            To the lock ");            Long startTime = System.currenttimemillis ();     for (; ;)                {if (System.currenttimemillis ()-startTime >= integer.max_value) break; Insert Data}} finally {System.out.println (Thread.CurrentThread ().GetName () + "execute finally");            Lock.unlock ();        System.out.println (Thread.getname () + "release lock");    }}} class MyThread extends Thread {private Test test = null;    Public MyThread (test test) {this.test = test;        } @Override public void Run () {try {Test.insert (Thread.CurrentThread ());        } catch (Interruptedexception e) {System.out.println (Thread.CurrentThread (). GetName () + "interrupted"); }    }}

After running, it is found that thread2 can be properly interrupted.

3.ReadWriteLockReadwritelock is also an interface in which only two methods are defined:
Public interface Readwritelock {    /**     * Returns the lock used for reading.     *    /Lock readlock ();     /**     * @return The lock used for writing.     *    /Lock writelock ();}
One is used to obtain a read lock, and one to obtain a write lock. This means separating the read and write operations of the file into 2 locks to be allocated to the thread, allowing multiple threads to read concurrently. The following reentrantreadwritelock implements the Readwritelock interface.

4.ReentrantReadWriteLock
Reentrantreadwritelock provides a lot of rich methods, but the main one is two methods: Readlock () and Writelock () are used to obtain read and write locks.
Here are a few examples to look at Reentrantreadwritelock specific usage.
If there are multiple threads to read at the same time, take a look at the effect synchronized achieves:
public class Test {    private Reentrantreadwritelock rwl = new Reentrantreadwritelock ();         public static void Main (string[] args)  {        final Test test = new test ();                 New Thread () {public            void run () {                test.get (Thread.CurrentThread ());}            ;        }. Start ();                 New Thread () {public            void run () {                test.get (Thread.CurrentThread ());}            ;        }. Start ();             }            Public synchronized void get (thread thread) {        long start = System.currenttimemillis ();        while (System.currenttimemillis ()-start <= 1) {            System.out.println (thread.getname () + "reading operation");        }        System.out.println (Thread.getname () + "read operation completed");}    }

The output of this program will be until Thread1 performs a read operation before it prints thread2 information to perform the read operation.
Thread-0 reading Operation Thread-0 Reading operation Thread-0 reading Operation Thread-0 in progress Thread-0 read Operation Thread-1 in progress read Thread-1 reading Operation Thread-1 in read operation THR Ead-1 reading Operation Thread-1 Read operation completed

Instead of using a read-write lock:
public         Class Test {private Reentrantreadwritelock rwl = new Reentrantreadwritelock ();                 public static void Main (string[] args) {final Test test = new test ();            New Thread () {public void run () {Test.get (Thread.CurrentThread ());        };                 }.start ();            New Thread () {public void run () {Test.get (Thread.CurrentThread ());        };             }.start ();        public void get (thread thread) {Rwl.readlock (). Lock ();                         try {Long start = System.currenttimemillis ();            while (System.currenttimemillis ()-start <= 1) {System.out.println (Thread.getname () + "reading operation");        } System.out.println (Thread.getname () + "read operation completed");        } finally {Rwl.readlock (). Unlock (); }    }}

The printing results are:
Thread-0 reading Operation Thread-0 Reading operation Thread-1 reading operation Thread-0 in progress read Thread-1 reading Operation Thread-0 reading operation Thread-1 in-progress read Thread-1 reading Operation T Hread-1 is reading operation Thread-0 read operation completed Thread-1 read operation completed

Note that Thread1 and thread2 are simultaneously read operations. This greatly improves the efficiency of the read operation.but it's important to note that, if a thread has already occupied a read lock, the thread that is requesting a write lock waits for the read lock to be freed if the other thread is to request a write lock. If a thread has already occupied a write lock, the requested thread waits for the write lock to be released when another thread requests a write lock or read lock.

selection of 5.Lock and synchronized
In summary, lock and synchronized have the following differences:
1) lock is an interface, and synchronized is the key word in Java, synchronized is a built-in language implementation;
2) When an exception occurs, synchronized automatically releases the lock that the thread occupies, so it does not cause a deadlock, and in the event of an exception, lock is likely to cause a deadlock if it does not voluntarily release the lock through Unlock (). Therefore, lock must be released in the finally block when using lock;
3) lock allows the thread waiting for the lock to respond to interrupts, while synchronized does not, while using synchronized, the waiting thread waits and fails to respond to interrupts;
4) lock can be used to know if there is a successful acquisition of locks, and synchronized is unable to do.
5) lock can improve the efficiency of multiple threads for read operations.
In terms of performance, if competitive resources are not intense, the performance of both is similar, and when competitive resources are very intense (that is, there are a lot of threads competing at the same time), then lock performance is far better than synchronized. Therefore, in the specific use, according to the appropriate circumstances to choose.

Three, the related concept of lock introduction 1. Can be re-entered lock
If the lock is reentrant, it is referred to as a reentrant lock. Like synchronized and Reentrantlock are reentrant locks, reentrant. In my opinion, it actually shows the allocation mechanism of locks: thread-based allocation rather than method-invocation-based allocations. As a simple example, when a thread executes to a synchronized method, such as Method1, and another synchronized method Method2 is called in method1, the thread does not have to reapply for the lock. Instead, the method method2 can be executed directly.
Look at the following code to understand:
Class MyClass {public    synchronized void Method1 () {        method2 ();    }         Public synchronized void Method2 () {             }}

The two methods in the above code METHOD1 and method2 are decorated with synchronized, if a moment, thread a executes to method1, at this time thread a acquires the lock of this object, and because Method2 is also synchronized method, If synchronized is not reentrant, thread a needs to re-apply the lock. However, this can cause a problem because thread a already holds the lock on the object and is requesting a lock on the object, so that thread a waits for a lock that is never acquired.
This is not possible because synchronized and lock have reentrant features.

2. Interruptible Lock
Interruptible Lock: As the name implies, is a lock that can be broken accordingly.
In Java, synchronized is not an interruptible lock, and lock is an interruptible lock.
If a thread A is executing the code in the lock, and another threads B is waiting to acquire the lock, it may be because the wait time is too long, and the other thing is not waiting, and we can let it break itself or interrupt it in another thread, which is an interruptible lock.
The use of lockinterruptibly () has been demonstrated in the preceding example to demonstrate the interruptible nature of lock.

3. Fair lock
A fair lock is to obtain the lock in the order in which the lock is requested. For example, there are multiple threads waiting for a lock, and when the lock is released, the thread that waits the longest (the first requested thread) gets the one, and this is the fair lock.
An unfair lock does not guarantee that locks are obtained in the order in which they are requested. This can cause some or some threads to never get locks.
In Java, synchronized is a non-fair lock that does not guarantee the order in which the waiting thread acquires the lock.
For Reentrantlock and Reentrantreadwritelock, it is a non-fair lock by default, but can be set to a fair lock.
We can set the fairness of the lock in the following ways when we create the Reentrantlock object:
Reentrantlock lock = new Reentrantlock (true);
If the argument is true for a fair lock, the Fasle is a non-fair lock. By default, if you use the parameterless constructor, a non-fair lock is used.

4. Read/write lock
A read-write lock divides access to a resource (such as a file) into 2 locks, a read lock, and a write lock. It is because of the read-write lock that the read operation between multiple threads does not collide.
Readwritelock is a read-write lock, it is an interface, Reentrantreadwritelock implements this interface. Read locks can be obtained through Readlock (), and write locks are obtained through writelock ().
It can also be set to fair lock and non-fair lock in Reentrantreadwritelock. Remember, however, that Reentrantreadwritelock does not implement the lock interface, it implements theReadwritelockInterface.


Java Concurrency Programming: 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.