Java 简明教程
Java - Reentrant Monitor
Reentrant Monitor in Java
ReetrantLock 是一个实现 Lock 接口的类。它以极大的灵活性提供了 synchronization 特性,这也是它成为 Java 中使用最多的锁类的原因。它对于可靠和 fair working of thread 是必要的。线程是大型操作的小子进程。在本文中,我们将学习 ReetrantLock 以及它们如何管理线程以便高效工作。
ReetrantLock is a class that implements Lock Interface. It provides the synchronization feature with great flexibility which is why it is the most used lock class in Java. It is necessary for the reliable and fair working of thread. Here, threads are small sub-processes of a big operation. In this article, we are going to learn ReetrantLock and how they manage threads so that they can work efficiently.
Working of ReetrantLock
当 multiple threads 尝试访问共享资源时,ReetrantLock 一次将访问限制到一个线程,通过 lock() 和 unlock() 方法。假设有三个试图预订火车票的人。同时,这三个人都将尝试访问预订系统,可能会有两个人最终预订了同一个座位。Reetrant Lock 可以处理这种情况。
When multiple threads try to access a shared resource then, ReetrantLock restricts access to a single thread at a time through lock() and unlock() methods. Suppose there are three people trying to book a train ticket. At the same time, all three people will try to access the booking system, it may happen that two people end up booking the same seat. Reetrant Lock can handle this situation.
首先,这 3 个人都会请求通过*tryLock()*方法获取预订系统。当一个人获取预订系统时,它会通过*lock()*方法限制特定座位预订。预订后,该人将调用*unlock()*方法以释放获取的锁。在资源繁忙前,其他的人将会在队列中排队等待轮到他们,并在锁释放后进入可运行状态。
First, all three people will request to acquire the booking system through tryLock() method. When one acquires the booking system then, it restricts the particular seat booking through lock() method. After booking, the person will call the unlock() method to release the acquired lock. Till the resources are busy other people will wait in a queue for their turn and after the release of lock they will come in a runnable state.
ReetrantLock 尝试公平地提供锁。我们可以设置线程可以获取锁的时间,并且还可以确保等待时间最长的线程可能首先获取锁。默认情况下,锁是不公平的,要使它公平,我们需要在其构造函数中传递布尔值*true*。
ReetrantLock tries to provide locks in a fair manner. We can set for how long a thread can acquire lock and also, it ensures that a thread with the longest wait time may get access to lock first. By default the locks are unfair, to make it fair we need to pass Boolean value true in its constructor.
Syntax
ReentrantLock nameOflock = new ReentrantLock();
// by default false
Or,
ReentrantLock nameOflock = new ReentrantLock(true);
// we can make it true
该锁是显式的,可以按任何顺序锁定或解锁。单个线程可以多次要求锁,这就是锁名称为 Reentrant 的原因。我们可以使用*getHoldCount()*方法计算锁获取的次数。
The locks are explicit and can lock or unlock in any order. A single thread can ask for the lock multiple times that’s the reason the name of lock is Reentrant. We can count the number of times a lock is acquired by using getHoldCount() method.
Multithreading Without Reentrant Lock
以下示例说明了在上述代码中不使用 Reetrant Lock 的多线程。我们创建了一个类 Thrd,其中包含方法 operation() 以执行给定的任务。现在我们创建了三个线程类并调用 operation() 方法。在 main() 方法中定义了三个线程类对象,并定义了它们的 start() method 以启动线程执行。
The following example illustrates the multithreading witout use of Reetrant Lock in above code. We’ve created a class Thrd with a method operation() to perform a given task. Now we’ve created three thread classes and call the operation() method. In the main() method, three objects of thread class are defined and their start() method to start the execution of threads.
Example of Multithreading Without Reentrant Lock
package com.tutorialspoint;
class Thrd {
static void operation(int data) {
for(int i = 1; i <= 4; i++) {
System.out.println(data++);
}
}
}
class Thrd1 extends Thread {
// thread number 1
public void run() {
Thrd.operation(1);
// method calling
}
}
class Thrd2 extends Thread {
// thread number 2
public void run() {
Thrd.operation(5);
// method calling
}
}
class Thrd3 extends Thread {
// thread number 3
public void run() {
Thrd.operation(10);
// method calling
}
}
public class TestThread {
public static void main(String args[]) {
// creating object for thread class
Thrd1 oprt1 = new Thrd1();
Thrd2 oprt2 = new Thrd2();
Thrd3 oprt3 = new Thrd3();
// Starting the thread operation
oprt1.start();
oprt2.start();
oprt3.start();
}
}
每次运行该程序都会产生不同的结果——
This produces a different result every time you run this program −
1
2
3
4
10
11
12
13
5
6
7
8
Multithreading With Reentrant Lock
以下示例演示了在以上代码中使用 Reentrant 锁。我们已经创建了一个类*Thrd*,并且在这个线程中,我们已经定义了一个 ReentrantLock 对象。一个方法 operation() 将*tryLock()*方法的布尔值存储到一个名叫*lockAcquired*的变量,这将检查锁是否被任何线程获取。如果获取到锁,则会使用*lock()*方法将锁提供给该线程,然后线程开始执行给定的任务。任务将在 try 块中执行,锁将在 finally 块中使用*unlock()*方法释放。现在我们已经创建了 3 个线程类并调用*operation()*方法。在 main() 方法中,定义了线程类的 3 个对象及其*start()*方法以开始执行线程。
The following example illustrates the use of Reetrant Lock in above code. We’ve created a class Thrd and inside this thread, we’ve defined an object of ReentrantLock. A method operation() store the Boolean value of tryLock() method to a variable named lockAcquired which will check if lock gets acquired by any thread or not. If the lock is acquired lock is given to that thread using lock() method and then the thread start performing the given task. The task will be performed in the try block and the lock will be released in the finally block using unlock() method. Now we’ve created three thread classes and call the operation() method. In the main() method, three objects of thread class are defined and their start() method to start the execution of threads.
Example of Multithreading With Reentrant Lock
package com.tutorialspoint;
import java.util.concurrent.locks.ReentrantLock;
class Thrd {
// creating object of ReentrantLock class
private static ReentrantLock lockr = new ReentrantLock();
static void operation(int data) {
// give access to lock
boolean lockAcquired = lockr.tryLock();
if (lockAcquired) {
try {
lockr.lock();
// giving lock to thread
for(int i = 1; i <= 4; i++) {
System.out.println(data++);
}
// checking lock count
System.out.println("Count of Lock: " + lockr.getHoldCount());
} finally {
lockr.unlock();
// unlocking the lock
}
} else {
System.out.println("I am in else block");
}
}
}
class Thrd1 extends Thread {
// thread number 1
public void run() {
Thrd.operation(1);
// method calling
}
}
class Thrd2 extends Thread {
// thread number 2
public void run() {
Thrd.operation(5);
// method calling
}
}
class Thrd3 extends Thread {
// thread number 3
public void run() {
Thrd.operation(10);
// method calling
}
}
public class TestThread {
public static void main(String args[]) {
// creating object for thread class
Thrd1 oprt1 = new Thrd1();
Thrd2 oprt2 = new Thrd2();
Thrd3 oprt3 = new Thrd3();
// Starting the thread operation
oprt1.start();
oprt2.start();
oprt3.start();
}
}
每次运行该程序都会产生不同的结果——
This produces a different result every time you run this program −
I am in else block
5
6
7
8
Count of Lock: 2
I am in else block
Multithreading With Reentrant Lock as True
以下示例演示了在以上代码中使用 Reentrant 锁。我们已经创建了一个类*Thrd*,并且在这个线程中,我们已经定义了一个 ReentrantLock 对象,其公平值为 true。一个方法 operation() 将*tryLock()*方法的布尔值存储到一个名叫*lockAcquired*的变量,这将检查锁是否被任何线程获取。如果获取到锁,则会使用*lock()*方法将锁提供给该线程,然后线程开始执行给定的任务。任务将在 try 块中执行,锁将在 finally 块中使用*unlock()*方法释放。现在我们已经创建了 3 个线程类并调用*operation()*方法。在 main() 方法中,定义了线程类的 3 个对象及其*start()*方法以开始执行线程。
The following example illustrates the use of Reetrant Lock in above code. We’ve created a class Thrd and inside this thread, we’ve defined an object of ReentrantLock with fair value as true. A method operation() store the Boolean value of tryLock() method to a variable named lockAcquired which will check if lock gets acquired by any thread or not. If the lock is acquired lock is given to that thread using lock() method and then the thread start performing the given task. The task will be performed in the try block and the lock will be released in the finally block using unlock() method. Now we’ve created three thread classes and call the operation() method. In the main() method, three objects of thread class are defined and their start() method to start the execution of threads.
Example of Multithreading With Reentrant Lock as True
package com.tutorialspoint;
import java.util.concurrent.locks.ReentrantLock;
class Thrd {
// creating object of ReentrantLock class
private static ReentrantLock lockr = new ReentrantLock(true);
static void operation(int data) {
// give access to lock
boolean lockAcquired = lockr.tryLock();
if (lockAcquired) {
try {
lockr.lock();
// giving lock to thread
for(int i = 1; i <= 4; i++) {
System.out.println(data++);
}
// checking lock count
System.out.println("Count of Lock: " + lockr.getHoldCount());
} finally {
lockr.unlock();
// unlocking the lock
}
} else {
System.out.println("I am in else block");
}
}
}
class Thrd1 extends Thread {
// thread number 1
public void run() {
Thrd.operation(1);
// method calling
}
}
class Thrd2 extends Thread {
// thread number 2
public void run() {
Thrd.operation(5);
// method calling
}
}
class Thrd3 extends Thread {
// thread number 3
public void run() {
Thrd.operation(10);
// method calling
}
}
public class TestThread {
public static void main(String args[]) {
// creating object for thread class
Thrd1 oprt1 = new Thrd1();
Thrd2 oprt2 = new Thrd2();
Thrd3 oprt3 = new Thrd3();
// Starting the thread operation
oprt1.start();
oprt2.start();
oprt3.start();
}
}
每次运行该程序都会产生不同的结果——
This produces a different result every time you run this program −
I am in else block
I am in else block
5
6
7
8
Count of Lock: 2