I. Synchronized function extension: Re-entry lock (Java.util.concurrent.locks.ReentrantLock)
A re-entry lock can completely replace the Synchronized keyword. In earlier versions of JDK 5.0, the ability to re-enter locks was much better than synchronized, but since JDK 6.0, the JDK has done a lot of optimizations on syn-chronized, making the performance gap between the two less significant.
public class Reenterlock implements runnable{
public static Reentrantlock lock=new Reentrantlock ();
public static int i=0;
@Override in Geneva
public void Run () {
j=0;j<10000000;j++ (int) {
Lock.lock ();
try{
i++;
Ten}finally{
Lock.unlock ();
12}
13}
14}
public static void Main (string[] args) throws Interruptedexception {
Reenterlock tl=new Reenterlock ();
The thread t1=new thread (TL);
Thread t2=new thread (TL);
T1.start (); T2.start ();
T1.join (); T2.join ();
System.out.println (i);
22}
23}
The re-entry lock has a displayed operating procedure compared to synchronized. The developer must manually specify when to lock and when to release the lock. Because of this, the flexibility of the re-entry lock is much better than synchronized for logical control. However, it is worth noting that when exiting the critical section, you must remember to release the lock.
Re-entry locks can be entered repeatedly, where the repetition is confined to only one thread. The 7th to 12th line of the above code can be written in the following form:
Lock.lock ();
Lock.lock ();
try{
i++;
}
finally{
Lock.unlock ();
Lock.unlock ();
}
The re-entry lock also provides some advanced features. For example, a re-entry lock can provide the ability to interrupt processing.
1. Interrupt response
For synchronized, if a thread waits for a lock, the result is only two cases, either it gets the lock to continue execution, or it remains waiting. The use of a re-entry lock provides another possibility that the thread can be interrupted. That is, in the process of waiting for a lock, the program can cancel the lock request as needed.
try {
Lock.lockinterruptibly (); Apply for a lock (replace the above Lock.lock ();)
}catch{}
Finally
{if (Lock.isheldbycurrentthread ()) {
Lock1.unlock ();
}
}
Available through T2.interrupt (); Interrupt to notify and capture release lock
2. Lock application Wait time limit
In addition to waiting for external notifications, there is another way to avoid deadlocks, which is to wait for a limited time.
We can use the Trylock () method to do a time-limited wait
if (Lock.trylock (5, Timeunit.seconds)) {}
else {}
The Trylock () method receives two parameters, one representing the wait length, and the other representing the timing unit.
The Reentrantlock.trylock () method can also be run without parameters directly. In this case, the current thread attempts to acquire the lock, and if the lock is not occupied by another thread, the request lock succeeds and returns true immediately. If the lock is occupied by another thread, the current thread does not wait, but returns false immediately. This mode does not cause threads to wait, and therefore does not create deadlocks
3. Fair lock
If we use the Synchronized keyword for lock control, then the resulting lock is not fair.
and the re-entry lock allows us to set the fairness of it. It has one of the following constructors:
Public Reentrantlock (Boolean fair)
When the parameter fair is true, the lock is fair. Fair locks look beautiful, but to achieve a fair lock requires the system to maintain an orderly queue, so the fair lock implementation cost is relatively high, the performance is also very low, so by default, the lock is not fair. If there is no special requirement, no fair lock is required. Fair lock and unfair lock on-line scheduling performance is also very different.
For a non-fair lock, depending on the scheduling of the system, a thread will tend to acquire the lock already held, which is efficient, but not fair.
The
Several important methods for Reentrantlock above are organized as follows.
? Lock (): Gets the lock and waits if the lock is already occupied.
? lockinterruptibly (): Gets the lock, but the priority response is interrupted.
? Trylock (): Attempts to obtain a lock, if successful, returns True, and the failure returns false. The method does not wait and returns immediately.
? Trylock (long time, Timeunit unit): attempts to acquire a lock for a given period.
? Unlock (): Releases the lock.
in the implementation of the re-entry lock, it is mainly focused on the Java level. In the implementation of the re-entry lock, there are three main features:
First, the atomic state. Atomic states use CAS operations (discussed in detail in the 4th chapter) to store the state of the current lock and determine whether the lock has been held by another thread.
Second, the wait queue. All threads that do not have a request to the lock will enter the wait queue to wait. The system can wake up a thread from the waiting queue and continue to work after the lock is released on a wired path.
Third, blocking Primitive Park () and Unpark (), used to suspend and resume threads. Threads that do not get locks will be suspended. For more information about Park () and Unpark (), refer to the 3.1.7 Thread blocking Tool class: Locksupport.
Good partner for re-entry lock: Condition condition
It works roughly the same as the Wait () and notify () methods. But the wait () and notify () methods are used in collaboration with the Synchro-nized keyword, and condtion is associated with a reentrant lock. The condition Newcondition () method, which implements this interface through the lock interface (which is a re-entry lock), generates a condition instance that is bound to the current re-entry lock. With the condition object, we can allow the thread to wait at the right time, or to be notified at a particular moment, to continue execution.
The basic methods provided by the condition interface are as follows:
void await () throws interruptedexception;
void awaituninterruptibly ();
Long Awaitnanos (long nanostimeout) throws interruptedexception;
Boolean await (long time, Timeunit unit) throws Interruptedexception;
Boolean awaituntil (Date deadline) throws Interruptedexception;
void signal ();
void Signalall ();
The await () method causes the current thread to wait while releasing the current lock, and when the signal () or Sig-nalall () method is used in other threads, the thread will regain the lock and continue execution. Or you can jump out of the queue when the thread is interrupted. This is very similar to the Object.wait () method.
The awaituninterruptibly () method is basically the same as the await () method, but it does not respond to interruptions during the wait process.
The Singal () method is used to wake up a thread that is waiting. The relative Singalall () method wakes all the threads that are waiting. This and the Obejct.notify () method
Inside the JDK, the re-entry lock and condition objects are widely used, for example in Arrayblockingqueue, the put () method is implemented as follows:
Second, allow multiple threads simultaneous access: semaphore (Semaphore)
The semaphore provides a more powerful control method for multi-threaded collaboration. Broadly speaking, the semaphore is an extension of the lock. Whether it is an internal lock synchronized or a re-entry lock Reentrantlock, only one thread is allowed to access one resource at a time, and semaphores can specify multiple threads while accessing a resource.
The semaphore mainly provides the following constructors:
public Semaphore (int permits)
public Semaphore (int permits, Boolean fair)//The second parameter can specify whether it is fair
The main methods are:
public void Acquire ()
public void acquireuninterruptibly ()
public boolean Tryacquire ()
public boolean Tryacquire (long timeout, timeunit unit)
public void Release ()
Third, Readwritelock read and write lock
private static Reentrantreadwritelock Readwritelock=newreentrantreadwritelock ();
private static Lock Readlock = Readwritelock.readlock ();
private static Lock Writelock = Readwritelock.writelock ();
Read-read non-exclusive: No blocking between read and read.
Read-write Mutex: Read Block write, write will also block read.
Write-Write Mutex: write-write blocking. If the number of read operations in the system is much greater than the write operation, the read-write lock can maximize the effectiveness of the system to improve performance.
Four, countdown timer: Countdownlatch
for a countdown timer, a typical scenario is a rocket launch. Before the launch of the rocket, in order to ensure foolproof, often have to carry out various equipment, instrument inspection. The engine can only fire after all the checks have been completed. This scenario is ideal for using Countdownlatch. It allows the ignition thread to wait for all the check threads to complete before executing.
Constructor:
Public countdownlatch (int count)
Countdownlatch end = new Countdownlatch (10);//Create instance Count of 10. This means that 10 threads are required to complete the task and wait for the thread on the Countdownlatch to continue execution.
End.countdown ();//Notify Count-downlatch, a thread has completed the task, the countdown timer can be reduced by 1.
End.await ();//wait for the main thread to wait for all 10 check tasks to complete. After 10 tasks are complete, the main thread can continue to execute.
Five, circular fence: cyclicbarrier
Cyclicbarrier is another multi-threaded concurrency control utility. Very similar to Countdownlatch, it can also achieve count waits between threads, but its functionality is more complex and powerful than Countdown-latch.
The front cyclic means a loop, which means the counter can be used repeatedly. For example, if we set the counter to 10, then after the first 10 threads, the counter will be zeroed, and then the next batch of 10 threads will be aligned, which is the meaning of the loop fence.
The use of Cyclicbarrier is also plentiful. For example, the commander issued an order requiring 10 soldiers to complete a task together. At this point, 10 soldiers will be asked to assemble the report, then, together valiantly poised to carry out the task. When 10 soldiers carry out their task at hand, the commander can announce the mission and finish it!
Slightly more powerful than Countdownlatch, Cyclicbarrier can receive a parameter as a barrierac-tion. The so-called barrieraction is the action that the system performs when the counter is counted once. The following constructor, where parties represents the total count, which is the total number of threads involved.
public Cyclicbarrier (int parties, Runnable barrieraction)
Cyclicbarrier cyclic = new Cyclicbarrier (n, New Barrierrun (flag, N));
Cyclic.await ();
The Cyclicbarrier.await () method may throw two exceptions.
One is interruptedexception, that is, in the waiting process, the thread is interrupted, it should be said that this is a very common exception. Most of the methods that force the thread to wait can throw this exception, allowing the thread to still respond to external emergencies while waiting.
Another exception is Cyclicbarrier's unique brokenbarrierexception. Once this exception is encountered, it means that the current cyclicbarrier is broken, and there may be no way for the system to wait for all threads to be aligned. If you continue to wait, it may be futile, so the local bulk, go home.
Vi. Thread blocking Tool class: Locksupport
Locksupport is a handy and useful threading tool that can block threads anywhere in the thread. Compared to Thread.Suspend (), it makes up for situations where the thread cannot continue because the resume () occurred before. Compared to ob-ject.wait (), it does not need to obtain a lock on an object first, and does not throw a interruptedexception exception. Locksupport static Method Park () can block the current thread, similar to Parknanos (), Parkuntil (), and other methods. They achieve a time-limited wait.
Locksupport.park (); Blocking thread T1
Locksupport.unpark (t1); Release blocking
Of course, we still cannot guarantee that the Unpark () method will occur after the park () method. But by executing this code, you'll see that it ends up as normal all the time, and does not cause the thread to hang permanently because of the park () method.
This is because the Locksupport class uses a mechanism similar to semaphore. It prepares a license for each thread, and if the license is available, the park () function returns immediately and consumes the license (that is, the license becomes unavailable), which is blocked if the license is not available. and Unpark () makes a license available (but unlike the semaphore, the license does not accumulate and you cannot have more than one license, it will always be one). This feature makes it possible for the next park () operation to return immediately, even if the Unpark () operation occurs before Park (). This is the main reason why the above code can be successfully ended.
At the same time, a thread in park () hangs does not give a puzzling runnable state like Sus-pend (). It will give a waiting state very clearly, and it will even be marked by Park ().
In addition, if you use the park (object) function, you can also set a blocking object for the current thread. This blocking object will appear in the thread dump. This makes it more convenient to analyze the problem. In the stack information, we can see the object that the current thread waits for.
In addition to the function of timed blocking, the Locksup-port.park () can also support interrupt effects. However, unlike other functions that receive interrupts, Locksupport.park () does not throw a interruptedexception exception. It just returns silently, but we can get the interrupt token from the thread.interrupted () method.
Multi-threaded team collaboration for JDK concurrency tools: synchronization Control