The Java.util.concurrent.locks package provides a framework interface and class for lock and wait conditions, unlike built-in synchronization and monitors. The framework allows for more flexibility in using locks and conditions, but at the expense of more difficult syntax.
The lock interface supports locking rules that differ in semantics (reentrant, fair, and so on) and can be used in the context of non-blocking structures, including Hand-over-hand and lock rearrangement algorithms. The main implementation is reentrantlock.
The Readwritelock interface defines in a similar way some locks that a reader can share while the writer is exclusive. This package only provides an implementation, that is, Reentrantreadwritelock, because it applies to most of the standard usage contexts. But programmers can create their own implementations that apply to non-standard requirements.
The following is a related class diagram for the locks package:
Before we synchronized a piece of code or object using the Synchronized keyword, using the built-in features of the Java language, however, Synchronized's features also lead to problems in many scenarios, such as:
On a synchronization resource, thread a first obtains the lock on the resource and begins execution, at which point other threads that want to manipulate the resource must wait. If thread A is in a long-running state for some reason, such as waiting for the network, repeatedly retrying, and so on. then other threads will not be able to handle their tasks in a timely manner, and can only wait indefinitely. if thread A's lock is automatically freed after it has been held for some time, will other threads be able to use that resource? is it similar to a shared and exclusive lock in a database, or can it be applied to an application? Therefore, the introduction of lock mechanism can be a good solution to these problems.
Lock provides more features than synchronized. But pay attention to the following points:
? Lock is not built into the Java language, synchronized is a keyword in the Java language and is therefore a built-in feature. Lock is a class that enables simultaneous access through this class;
? Lock and synchronized a very big difference, the use of synchronized does not require the user to manually release the lock, when the synchronized method or synchronized code block execution, the system will automatically allow the thread to release the use of the lock; and lock must be the user to manually release the lock, if there is no active release of the lock, it is possible to cause a deadlock phenomenon.
One, can re-enter the lock Reentrantlock
Think of the lock we generally think of is a synchronous lock is Synchronized, the introduction of the re-entry lock reentrantlock more efficient. IBM introduces a re-entry lock: More flexible and scalable locking mechanism in JDK 5.0
Here is a brief introduction to the classification of reentrant locks: (assuming that thread a acquires the lock, a execution is now done, the lock is released and the thread B that is waiting to be awakened is awakened.) However, a wake-up operation to B may exist in the time of the real acquisition of the lock, the thread C has acquired the lock, resulting in the queue waiting for the B cannot obtain the lock)
1) Fair Lock:
Because B waits to be awakened first, in order to guarantee the fairness principle, the Fair lock will let B get the lock first.
2) Non-fair lock
It is not guaranteed that B gets to the lock object first.
Both locks can be distinguished as long as the Reentrantlock object is constructed, when the argument is set to true for a fair lock, false for an unfair lock, and the default constructor creates a non-fair lock.
Private lock lock = new Reentrantlock (true);
Reentrantlock's Fair lock has made a great sacrifice in performance and effectiveness, and can be consulted in the article that was sent by IBM.
Second, the condition variable Condition
Condition is an interface under the Java.util.concurrent.locks package, and the Condition interface describes the condition variables that may be associated with the lock. These variables are similar in usage to implicit monitors that use object.wait access, but provide more powerful functionality. It should be noted that a single Lock may be associated with multiple Condition objects. To avoid compatibility issues, the name of the Condition method differs from the corresponding Object version.
Condition the object Monitor method (wait, notify, and Notifyall) into distinct objects to provide multiple wait set (Wait-set) for each object by combining these objects with any Lock implementation. Where Lock replaces the use of the Synchronized method and the statement, Condition replaces the use of the Object monitor method.
Condition (also known as a conditional queue or condition variable) provides a means for a thread to remain in a suspended state (that is, "wait") until a notification is received from another thread under a state condition. Because access to this shared state information occurs in different threads, it must be protected so that some form of lock is associated with the condition.
the Condition instance is essentially bound to a lock.
There is no longer an analysis of the source code under the locks package.
Three, Reentrantlock and condition design multi-threaded deposit and withdrawal
1. When depositing funds, you cannot withdraw money by wire. Withdrawals are not allowed on the wire at the time of deposit.
2. When withdrawing money, the balance is greater than the withdrawal amount to make the withdrawal operation, otherwise the balance is insufficient.
3. When withdrawing money, if the amount is insufficient, block the current thread, and wait for 2s (there may be other threads depositing the funds).
If there are no other threads within 2s to complete the deposit, or if the amount is insufficient, the print amount is insufficient.
If the other deposit is sufficient, notify the blocking thread and complete the withdrawal operation.
/*** Ordinary bank account, not overdraft*/ Public classMyCount {PrivateString OID;//Account Number Private intCash//account Balance//account lock, where a fair lock is used, a pending withdrawal thread takes precedence over the lock, rather than having the other deposit and withdrawal threads acquire the lock PrivateLock lock =NewReentrantlock (true); PrivateCondition _save = Lock.newcondition ();//Deposit Conditions PrivateCondition _draw = Lock.newcondition ();//Withdrawal ConditionsMyCount (String oid,intCash) { This. OID =OID; This. Cash =cash; } /*** Deposit *@paramx Action Amount *@paramname operator*/ Public voidSaving (intx, String name) {Lock.lock ();//Get lock if(X > 0) {Cash+ = x;//DepositSYSTEM.OUT.PRINTLN (name + "deposit" + x + ", current balance is" +cash); } _draw.signalall (); //wakes all waiting threads. Lock.unlock ();//Release Lock } /*** Withdrawal *@paramx Action Amount *@paramname operator*/ Public voidDrawingintx, String name) {Lock.lock ();//Get lock Try { if(Cash-x < 0) {System.out.println (name+ "in blocking"); _draw.await (2000,timeunit.milliseconds);//block the withdrawal operation, after which the lock is automatically released after the await, until it is automatically retrieved by Wake } if(cash-x>=0) {Cash-= x;//WithdrawalsSYSTEM.OUT.PRINTLN (name + "withdrawal" + x + ", current balance is" +cash); }Else{System.out.println (name+ "The balance is insufficient, the current balance is" +cash+ "the withdrawal amount is" +x); } //Wake up all deposit operations, there is no practical effect here because there is no blocking operation in the deposit code_save.signalall (); } Catch(interruptedexception e) {e.printstacktrace (); } finally{lock.unlock ();//Release Lock } }}
Here the reentrant lock can also be set to an unfair lock, so blocking the withdrawal thread may be associated with other deposit and withdrawal operations.
/*** Deposit Thread class*/ Static classSavethreadextendsThread {PrivateString name;//Operating Person PrivateMyCount MyCount;//Account Private intX//Deposit AmountSavethread (String name, MyCount MyCount,intx) { This. Name =name; This. MyCount =MyCount; This. x =x; } Public voidrun () {mycount.saving (x, name); } } /*** Withdrawal Thread class*/ Static classDrawthreadextendsThread {PrivateString name;//Operating Person PrivateMyCount MyCount;//Account Private intX//Deposit AmountDrawthread (String name, MyCount MyCount,intx) { This. Name =name; This. MyCount =MyCount; This. x =x; } Public voidrun () {mycount.drawing (x, name); } } Public Static voidMain (string[] args) {//Create a concurrent access accountMyCount MyCount =NewMyCount ("95599200901215522", 1000); //Create a pool of threadsExecutorservice pool = Executors.newfixedthreadpool (3); Thread T1=NewSavethread ("Zhang San", MyCount, 100); Thread T2=NewSavethread ("John Doe", MyCount, 1000); Thread T3=NewDrawthread ("Harry", MyCount, 12600); Thread T4=NewSavethread ("Lao Zhang", MyCount, 600); Thread T5=NewDrawthread ("Lao Niu", MyCount, 2300); Thread T6=NewDrawthread ("Fat", MyCount, 1800); Thread T7=NewSavethread ("Test", MyCount, 200); //Executing individual threadsPool.execute (t1); Pool.execute (T2); Pool.execute (T3); Pool.execute (T4); Pool.execute (T5); Pool.execute (T6); Pool.execute (T7); Try{Thread.Sleep (3000); } Catch(interruptedexception e) {e.printstacktrace (); } //Close the thread poolPool.shutdown (); }}
The above class defines the threads for multiple accessors, and the execution results are as follows:
S1 Deposit 100, current balance is 1100
S3 deposit 600, current balance is 1700
D2 in blocking
S2 Deposit 1000, current balance is 2700
D2 withdrawal 2300, current balance is 400
D3 in blocking
S4 deposit 200, current balance is 600
D3 balance is insufficient, current balance is 600 withdrawal amount is 1800
D1 in blocking
D1 balance is insufficient, current balance is 600 withdrawal amount is 12600
The following steps are performed:
- Initialize the account with a balance of 100.
- S1,S3 to complete the deposit.
- D2 withdrawals, insufficient balance, release the lock and block the thread, into the waiting queue.
- S2 when the deposit operation is completed, the suspended thread is awakened, and D2 completes the withdrawal.
- D3 withdrawals, insufficient balance, release the lock and block the thread, into the waiting queue.
- S4 after completing the deposit operation, wake up D3, but still insufficient balance, D3 withdrawal failed.
- D1 withdrawals, waits for 2s minutes, no thread wakes it up, and the withdrawals fail.
It is important to note that when condition calls the await () method, the current thread releases the lock (otherwise it is no different from the sychnize)
When you change a lock in a bank account to an unfair lock, the results are as follows:
The withdrawal amount is 23001100 withdrawal amount is 12600
D2 withdrawal after the balance is insufficient, release the lock and enter the waiting state. But when the S2 thread completes the deposit and does not immediately execute the D2 thread, it is D3 queue.
The difference between a fair lock and an unfair lock can be seen by executing the result, and a fair lock ensures that the waiting thread is first executed, but a non-fair lock may be queued by another thread.
Iv. application of Reentrantlock and condition in Arrayblockingqueue
The most typical application of the JDK source code for a reentrant lock is blockingqueue, which is likely to be known from the member variables in its source code (Arrayblockingqueue, for example):
/** the Queued items */ final object[] items; /** Items index for next take, poll, peek or remove */ int takeindex; /** Items index for next put, offer, or add */ int putindex; /** number of elements in the queue */ int count; / * * Concurrency control uses the classic two-condition algorithm * found in any textbook. */ /** Main Lock Guarding All access */
Primary troubleshooting thread security for multithreaded Access final Reentrantlock lock; /** Condition for waiting takes */
//Add element, wake consuming thread through Notempty (waiting for the condition) Private final Condition Notempty; /** Condition for waiting puts */
When the element is deleted, the build thread is awakened by Notfull (waiting for the condition) private final Condition notfull;
Arrayblockingqueue is a typical producer-consumer model that preserves elements through an array. To ensure thread safety for adding and removing elements, reentrant locks and condition variables are added.
A reentrant lock is a key guarantee that multithreading is thread-safe for blocking queues, and conditional variables are introduced in order for the blocked consumer or producer to be automatically awakened.
When the queue is full, the producer is blocked, and if the customer consumes an element, the blocked producer is automatically awakened and the element is added to the queue.
The above two examples show the flexibility and practicality of the reentrantlock and condition under the Java.util.concurrent.locks package.
Reference:
Re-entry Lock introduction: 52345422
IBM about Lock Introduction: http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html
http://286.iteye.com/blog/2296249
Java concurrent Programming--bank deposit and withdrawal via reentrantlock,condition