当前位置:网站首页>Four pits in reentrantlock!

Four pits in reentrantlock!

2022-07-05 01:05:00 Brother Lei talks about programming


ReentrantLock Medium 4 Pit !_java

JDK 1.5 Before synchronized Its performance is relatively low , But in JDK 1.5 in , Officially launched a heavyweight feature Lock, Changed... In one fell swoop Java Middle lock pattern .JDK 1.5 When we talked about locks before , Only built-in locks can be used synchronized, But now we have an explicit lock in our lock implementation Lock.

In the previous article, we have introduced synchronized, See the following list for details :

​《synchronized Lock this and class The difference between !》​

​《synchronized Lock expansion mechanism of optimization means !》​

​《synchronized Medium 4 An optimization , How many do you know? ?》​

So let's focus on Lock.

Lock brief introduction

Lock It's a top-level interface , All its methods are shown in the figure below :

ReentrantLock Medium 4 Pit !_ Fair lock _02

Its subclasses are listed below :

ReentrantLock Medium 4 Pit !_ Lock _03

We usually use them ReentrantLock To define its instance , The relationship between them is shown in the figure below :

ReentrantLock Medium 4 Pit !_ Fair lock _04


PS:Sync It means synchronous lock ,FairSync It's a fair lock ,NonfairSync Fair lock .


ReentrantLock Use

Learning any skill starts with using , So we are no exception , Let's take a look at ReentrantLock The basic use of :

       
public class LockExample {
// Create lock object
private final ReentrantLock lock = new ReentrantLock();
public void method() {
// Lock operation
lock.lock();
try {
// Business code ......
} finally {
// Release the lock
lock.unlock();
}
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

ReentrantLock After creation , There are two key operations :


  • Lock operation :lock()
  • Release lock operation :unlock()

ReentrantLock Pit in

1.ReentrantLock Default to unfair lock

A lot of people will think ( Especially novice friends ),ReentrantLock The default implementation is fair lock , Not really ,ReentrantLock By default, it is an unfair lock ( This is mainly due to performance considerations ), For example, the following code :

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object
private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
// Define thread tasks
Runnable runnable = new Runnable() {
@Override
public void run() {
// Lock
lock.lock();
try {
// Print the name of the execution thread
System.out.println(" Threads :" + Thread.currentThread().getName());
} finally {
// Release the lock
lock.unlock();
}
}
};
// Create multiple threads
for (int i = 0; i < 10; i++) {
new Thread(runnable).start();
}
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_java_05

As can be seen from the results of the above execution ,ReentrantLock By default, it is an unfair lock . Because the name of the thread is incremented according to the order of creation , So if it's a fair lock , Then the execution of threads should be incremented in order , But from the above results, we can see , The execution and printing of threads are out of order , This explanation ReentrantLock By default, it is an unfair lock .

Want to ReentrantLock Setting a fair lock is also simple , Just create ReentrantLock when , Set up a true The construction parameters of , As shown in the following code :

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object ( Fair lock )
private static final ReentrantLock lock = new ReentrantLock(true);

public static void main(String[] args) {
// Define thread tasks
Runnable runnable = new Runnable() {
@Override
public void run() {
// Lock
lock.lock();
try {
// Print the name of the execution thread
System.out.println(" Threads :" + Thread.currentThread().getName());
} finally {
// Release the lock
lock.unlock();
}
}
};
// Create multiple threads
for (int i = 0; i < 10; i++) {
new Thread(runnable).start();
}
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_java_06

As can be seen from the above results , When we explicitly give ReentrantLock Set up true After the construction parameters of ,ReentrantLock It becomes a fair lock , The order in which threads acquire locks has also become orderly .

Actually from ReentrantLock We can also see whether it is a fair lock or an unfair lock ,ReentrantLock Part of the source code implementation is as follows :

       
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

From the above source code can be seen , By default ReentrantLock Will create an unfair lock , If you explicitly set the value of the construction parameter to true when , It will create a fair lock .

2. stay finally Middle release lock

Use ReentrantLock Be sure to release the lock when , Otherwise, the lock will be occupied all the time , Other threads that use the lock will wait forever , So we're using ReentrantLock when , Must be in finally Middle release lock , This ensures that the lock will be released .

Counter example

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// Lock operation
lock.lock();
System.out.println("Hello,ReentrantLock.");
// An exception will be reported here , The lock cannot be released normally
int number = 1 / 0;
// Release the lock
lock.unlock();
System.out.println(" Lock released successfully !");
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_java_07

As can be seen from the above results , When an exception occurs, the lock is not normally released , This will cause other threads using the lock to be permanently waiting .

Example

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// Lock operation
lock.lock();
try {
System.out.println("Hello,ReentrantLock.");
// An exception will be reported here
int number = 1 / 0;
} finally {
// Release the lock
lock.unlock();
System.out.println(" Lock released successfully !");
}
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_java_08

As can be seen from the above results , Although there are exceptions in the method , But it doesn't affect ReentrantLock Lock release operation , In this way, other threads using this lock can acquire and run normally .

3. The lock cannot be released more than once

lock Number of operations and unlock The number of operations must correspond one by one , And a lock cannot be released multiple times , Because this will cause the program to report an error .

Counter example

once lock It corresponds to twice unlock operation , Cause the program to report an error and terminate the execution , The sample code is as follows :

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object
private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
// Lock operation
lock.lock();

// Release the lock for the first time
try {
System.out.println(" Executive business 1~");
// Business code 1......
} finally {
// Release the lock
lock.unlock();
System.out.println(" Lock release lock ");
}

// Release the lock a second time
try {
System.out.println(" Executive business 2~");
// Business code 2......
} finally {
// Release the lock
lock.unlock();
System.out.println(" Lock release lock ");
}
// The last print operation
System.out.println(" Program execution complete .");
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_java_09

As can be seen from the above results , Execution section 2 individual unlock when , The program reported an error and terminated execution , The code that causes the exception does not execute normally .

4.lock Don't put it on try In code

In the use of ReentrantLock when , Be careful not to put the locking operation in try In the code , This will lead to the successful release of the lock without locking , This leads to abnormal program execution .

Counter example

       
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
// Create lock object
private static final ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
try {
// This is abnormal
int num = 1 / 0;
// Lock operation
lock.lock();
} finally {
// Release the lock
lock.unlock();
System.out.println(" Lock release lock ");
}
System.out.println(" Program execution complete .");
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

The results of the above procedures are as follows :

ReentrantLock Medium 4 Pit !_ Lock _10

As can be seen from the above results , If you put the locking operation on try In the code , It may lead to two problems :


  1. The lock is released successfully without locking , This leads to a new exception ;
  2. The exception of releasing the lock will overwrite the original exception of the program , This increases the difficulty of troubleshooting .

summary

This paper introduces Java Explicit locks in Lock And its subclasses ReentrantLock How to use and pay attention to ,Lock stay Java It occupies half of the lock , But in use, we should pay attention to 4 A question :


  1. By default ReentrantLock For a non fair lock, not a fair lock ;
  2. The number of locks added and released must be consistent , Otherwise, it will cause thread blocking or program exception ;
  3. The locking operation must be placed in try Before code , This can avoid the exception of successfully releasing the lock without locking ;
  4. The release lock must be placed in finally in , Otherwise, it will cause thread blocking .​


Pay attention to the company 「Java Chinese community 」 See more interesting 、 Intellectual Java Concurrent articles .



Follow the QR code below , Subscribe to more .

ReentrantLock Medium 4 Pit !_ Fair lock _11

author : Wang lei's blog

原网站

版权声明
本文为[Brother Lei talks about programming]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202141055326348.html