Java 简明教程

Java - Reentrant Monitor

Reentrant Monitor in Java

ReetrantLock 是一个实现 Lock 接口的类。它以极大的灵活性提供了 synchronization 特性,这也是它成为 Java 中使用最多的锁类的原因。它对于可靠和 fair working of thread 是必要的。线程是大型操作的小子进程。在本文中,我们将学习 ReetrantLock 以及它们如何管理线程以便高效工作。

Working of ReetrantLock

multiple threads 尝试访问共享资源时,ReetrantLock 一次将访问限制到一个线程,通过 lock()unlock() 方法。假设有三个试图预订火车票的人。同时,这三个人都将尝试访问预订系统,可能会有两个人最终预订了同一个座位。Reetrant Lock 可以处理这种情况。

首先,这 3 个人都会请求通过*tryLock()*方法获取预订系统。当一个人获取预订系统时,它会通过*lock()*方法限制特定座位预订。预订后,该人将调用*unlock()*方法以释放获取的锁。在资源繁忙前,其他的人将会在队列中排队等待轮到他们,并在锁释放后进入可运行状态。

ReetrantLock 尝试公平地提供锁。我们可以设置线程可以获取锁的时间,并且还可以确保等待时间最长的线程可能首先获取锁。默认情况下,锁是不公平的,要使它公平,我们需要在其构造函数中传递布尔值*true*。

Syntax

ReentrantLock nameOflock = new  ReentrantLock();
// by default false
Or,
ReentrantLock nameOflock = new  ReentrantLock(true);
// we can make it true

该锁是显式的,可以按任何顺序锁定或解锁。单个线程可以多次要求锁,这就是锁名称为 Reentrant 的原因。我们可以使用*getHoldCount()*方法计算锁获取的次数。

Multithreading Without Reentrant Lock

以下示例说明了在上述代码中不使用 Reetrant Lock 的多线程。我们创建了一个类 Thrd,其中包含方法 operation() 以执行给定的任务。现在我们创建了三个线程类并调用 operation() 方法。在 main() 方法中定义了三个线程类对象,并定义了它们的 start() method 以启动线程执行。

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();
   }
}

每次运行该程序都会产生不同的结果——

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()*方法以开始执行线程。

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();
   }
}

每次运行该程序都会产生不同的结果——

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()*方法以开始执行线程。

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();
   }
}

每次运行该程序都会产生不同的结果——

I am in else block
I am in else block
5
6
7
8
Count of Lock: 2