21, Java concurrency and multi-threaded-java lock

Source: Internet
Author: User
Tags throw exception

Tag: Lock otherwise bool thread communication is judged to contain an exception re-entry nal

The following is transferred from http://ifeve.com/locks/:

Locks, like synchronized synchronous blocks, are a thread synchronization mechanism, but more complex than the synchronized synchronization blocks in Java. Because locks (and other more advanced thread synchronization mechanisms) are implemented by synchronized synchronous blocks, we are not yet completely free of the Synchronized keyword (the translator notes: This is the case before Java 5).

Starting with Java 5, the Java.util.concurrent.locks package contains the implementation of some locks, so you don't have to implement your own locks. But you still need to know how to use these locks, and it's useful to understand the theory behind them. You can refer to my introduction to Java.util.concurrent.locks.Lock for more information about locks.

The following are the topics covered in this article:

A simple lock.

Let's start with a synchronization block in Java:

 Public class counter{    privateint count = 0;      Public int Inc () {        synchronized(this) {            return + +count ;        }    }}

You can see that there is a synchronized (this) code block in the Inc () method. The code block guarantees that only one thread can execute return ++count at the same time. While the code in the synchronized synchronization block can be more complex, the simple operation of ++count is enough to express the meaning of thread synchronization.

The following counter class uses lock instead of synchronized to achieve the same purpose:

 Public class counter{    privatenew  Lock ();     Private int count = 0;      Public int Inc () {        lock.lock ();         int Newcount = + +count;        Lock.unlock ();         return newcount;}    }

The lock () method locks the lock instance object so that all threads that call the lock () method on the object are blocked until the unlock () method of the lock object is called.

Here is a simple implementation of the lock class:

 Public classlock{Private BooleanisLocked =false;  Public synchronized voidLock ()throwsinterruptedexception{ while(isLocked) {wait (); } isLocked=true; }     Public synchronized voidunlock () {isLocked=false;    Notify (); }}

Notice the while (isLocked) loop, which is also called "Spin lock". The spin lock and the Wait () and notify () methods are described in more detail in this article. When IsLocked is true, the thread calling lock () blocks the wait on the wait () call. To prevent the thread from receiving a notify () call and returning from Wait (also known as spurious wakeup), the thread will recheck the islocked condition to determine whether it is currently safe to continue execution or if it needs to wait again, instead of thinking that the thread has been awakened and can proceed safely. If isLocked is false, the current thread exits the while (isLocked) loop and sets isLocked back to true so that other threads that are calling the lock () method can lock on the lock instance.

When the thread completes the code in the critical section (between lock () and unlock (), it calls unlock (). Execution unlock () re-sets IsLocked to false and notifies (wakes) one of the threads (if any) that called the Wait () function in the lock () method.

Re-entry of the lock

The synchronized synchronization block in Java is reentrant. This means that if a Java thread enters the synchronized synchronization block in the code, and therefore obtains a lock on the thread that corresponds to the synchronization object used by the synchronization block, then it can enter another Java code block that is synchronized by the same pipe object. Here is an example:

 Public class reentrant{    publicsynchronized  outer () {        inner ();    }      Public synchronized inner () {        //dosomething    }}

Note that both outer () and inner () are declared as synchronized, which is equivalent in the Java and synchronized (this) block. If a thread calls outer (), it is not a problem to call inner () in outer () because both methods (code blocks) are synchronized by the same pipe object ("this"). If a thread already has a lock on a pipe object, it has access to all the blocks of code that are synchronized by the pipe object. This is reentrant. A thread can enter a block of code synchronized with any lock it already owns.

The lock implementations given earlier are not reentrant. If we rewrite the Reentrant class as follows, when the thread calls outer (), it will block at the Lock.lock () of the inner () method.

 Public class reentrant2{    new  Lock ();      Public outer () {        lock.lock ();        Inner ();        Lock.unlock ();    }      Public synchronized inner () {        lock.lock ();         // Do something         Lock.unlock ();    }}

The thread that calls outer () locks the lock instance first, and then continues to call inner (). In the inner () method, the thread will try to lock the lock instance again, and the result will fail (that is, the thread will be blocked) because the lock instance is already locked in the outer () method.

Two times lock () does not call unlock (), the second call to lock will block, after seeing the lock () implementation, you will find the reason is obvious:

 Public class lock{    booleanfalse;      Public synchronized void  throws  interruptedexception{        while(isLocked) {            wait () ;        }         true ;    }    ...}

Whether a thread is allowed to exit the lock () method is determined by the condition in the while loop (Spin lock). The current judging condition is that the lock operation is allowed only if islocked is false, regardless of which thread has locked it.

In order for this lock class to be reentrant, we need to make a small change to it:

 Public classlock{BooleanisLocked =false; Thread Lockedby=NULL; intLockedcount = 0;  Public synchronized voidLock ()throwsinterruptedexception{Thread Callingthread=Thread.CurrentThread ();  while(isLocked && Lockedby! =callingthread)        {Wait (); } isLocked=true; Lockedcount++; Lockedby=Callingthread; }     Public synchronized voidunlock () {if(Thread.curentthread () = = This. Lockedby) {Lockedcount--; if(Lockedcount = = 0) {isLocked=false;            Notify (); }        }    }    ...}

Notice that the current while loop (Spin lock) also takes into account the thread that has locked the lock instance. If the current lock object is not locking (isLocked = false), or if the current calling thread has locked the lock instance, then the while loop is not executed and the thread calling lock () can exit the method (Translator note: "Allowed to exit the method" In the current semantics, it means not calling wait () and causing blocking.

In addition, we need to record the number of times the same thread repeatedly locks a lock object. Otherwise, a unblock () call will unlock the entire lock, even if the current lock has been locked more than once. We do not want the lock to be lifted until the number of times the unlock () call has reached the corresponding lock () call.

Now this lock class is reentrant.

The fairness of the lock

Java's synchronized blocks do not guarantee the order in which they are attempted into their threads. Therefore, if multiple threads are constantly competing for access to the same synchronized synchronization block, there is a risk that one or more threads will never get access-that is, access is always assigned to other threads. This situation is called thread starvation. In order to avoid this problem, the lock needs to achieve fairness. The locks shown in this article are internally implemented with synchronized synchronization blocks, so they are not guaranteed to be fair. There is more discussion of this content in hunger and equity.

Call Unlock () in the Finally statement

It is important to call unlock () in the finally statement if lock is used to protect the critical section and the critical section is likely to throw an exception. This ensures that the lock object can be unlocked so that other threads can continue to lock it. The following is an example:

Lock.lock (); Try {    //docritical sections code,    //which may throw exception finally {    lock.unlock ();}

This simple structure guarantees that the lock object can be unlocked when the critical section throws an exception. If the unlock () is not called in the finally statement, when the critical section throws an exception, the lock object stays in the locked state forever, which causes all other threads that call lock () on the lock object to block.

21, Java concurrency and multi-threaded-java lock

Related Article

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.