Groovy Reentrant Monitor 怎么用?

文章导读
Previous Quiz Next ReentrantLock 是一个实现了 Lock 接口的 class。它提供了高度灵活的 同步 功能,因此是 Groovy 中使用最广泛的 lock class。对于线程的可靠和公平运行至关重要。这里,线程是大操作的小子进程。在本文中
📋 目录
  1. ReentrantLock 的工作原理
  2. 语法
  3. 示例 - 没有使用 ReentrantLock 的多线程
  4. 示例 - 使用 Reentrant Lock 实现多线程
  5. 示例 - 使用公平 Reentrant Lock
A A

Groovy - 可重入监视器



Previous
Quiz
Next

ReentrantLock 是一个实现了 Lock 接口的 class。它提供了高度灵活的 同步 功能,因此是 Groovy 中使用最广泛的 lock class。对于线程的可靠和公平运行至关重要。这里,线程是大操作的小子进程。在本文中,我们将学习 ReentrantLock 以及它们如何管理线程以实现高效工作。

ReentrantLock 的工作原理

当多个线程尝试访问共享资源时,ReentrantLock 通过 lock()unlock() 方法限制同一时间只有一个线程访问。假设有三个人试图预订火车票。同时,这三个人都会尝试访问订票系统,可能会出现两个人预订同一座位的状况。ReentrantLock 可以处理这种情况。

首先,这三个人都会通过 tryLock() 方法请求获取订票系统。当一个人获取订票系统后,它通过 lock() 方法限制特定座位的预订。预订完成后,此人会调用 unlock() 方法释放已获取的 lock。在资源繁忙期间,其他人会排队等待轮到自己,lock 释放后它们将进入 runnable 状态。

ReentrantLock 试图以公平的方式提供 lock。我们可以设置线程获取 lock 的时长,并且确保等待时间最长的线程优先获取 lock。默认情况下 lock 是非公平的,要使其公平,需要在其 constructor 中传入 Boolean 值 true

语法

ReentrantLock nameOflock = new  ReentrantLock(); 
// 默认 false
Or,
ReentrantLock nameOflock = new  ReentrantLock(true); 
// 可以设置为 true

这些 lock 是显式的,可以按任意顺序 lock 或 unlock。单个线程可以多次请求 lock,这就是 lock 名为 Reentrant 的原因。我们可以使用 getHoldCount() 方法计算 lock 被获取的次数。

示例 - 没有使用 ReentrantLock 的多线程

以下示例说明了上述代码中未使用 ReentrantLock 的多线程情况。我们创建了一个 Thrd class,包含 operation() 方法来执行给定任务。然后创建了三个 thread class 并调用 operation() 方法。在 main() 方法中,定义了三个 thread class 对象并调用它们的 start() 方法来启动线程执行。

Example.groovy

class Example {
   static void main(String[] args) {
      // 创建 thread class 对象
      Thread1 oprt1 = new Thread1();
      Thread2 oprt2 = new Thread2();  
      Thread3 oprt3 = new Thread3();
      // 启动线程操作
      oprt1.start();
      oprt2.start();  
      oprt3.start();
   }
}
class Utility {
   static void operation(int data) {    
      for(int i = 1; i <= 4; i++) {
         println(data++);
      }
   }
}
class Thread1 extends Thread {
   // 线程编号 1 
   public void run() {
      Utility.operation(1);
   }
}
class Thread2 extends Thread {
   // 线程编号 2 
   public void run() {
      Utility.operation(5);
   }
}
class Thread3 extends Thread {
   // 线程编号 3
   public void run() {
      Utility.operation(10);
   }
}

每次运行此程序都会产生不同的结果 −

输出

将产生以下结果−

1
2
3
4
10
11
12
13
5
6
7
8

示例 - 使用 Reentrant Lock 实现多线程

以下示例说明了上述代码中 Reentrant Lock 的使用。我们创建了一个类 Thrd,在这个 thread 中定义了一个 ReentrantLock 对象。方法 operation() 将 tryLock() 方法的 Boolean 值存储到名为 lockAcquired 的变量中,用于检查锁是否被任何 thread 获取。如果锁被获取,则使用 lock() 方法将锁授予该 thread,然后该 thread 开始执行给定的任务。任务将在 try 块中执行,并在 finally 块中使用 unlock() 方法释放锁。现在我们创建了三个 thread 类并调用 operation() 方法。在 main() 方法中,定义了三个 thread 类对象,并调用它们的 start() 方法来启动 thread 的执行。

Example.groovy

import java.util.concurrent.locks.ReentrantLock;

class Example {
   static void main(String[] args) {
      // 创建 thread 类对象
      Thread1 oprt1 = new Thread1();
      Thread2 oprt2 = new Thread2();  
      Thread3 oprt3 = new Thread3();
      // 启动 thread 操作
      oprt1.start();
      oprt2.start();  
      oprt3.start();
   }
}

class Utility {
   // 创建 ReentrantLock 类的对象
   private static ReentrantLock lockr = new  ReentrantLock();
   static void operation(int data) {
      // 尝试获取锁
      boolean lockAcquired = lockr.tryLock(); 
      if (lockAcquired) {
         try {
            lockr.lock(); 
            // 将锁授予 thread
            for(int i = 1; i <= 4; i++) {
               println(data++);
            }
            // 检查锁计数
            println("Count of Lock: " + lockr.getHoldCount());
         } finally {
            lockr.unlock(); 
            // 释放锁 
         }
      } else {
         println("I am in else block");
      }
   }
}

class Thread1 extends Thread {
   // thread 编号 1 
   public void run() {
      Utility.operation(1);
   }
}
class Thread2 extends Thread {
   // thread 编号 2 
   public void run() {
      Utility.operation(5);
   }
}
class Thread3 extends Thread {
   // thread 编号 3
   public void run() {
      Utility.operation(10);
   }
}

每次运行此程序都会产生不同的结果 −

输出

I am in else block
1
2
3
4
I am in else block
Count of Lock: 2

示例 - 使用公平 Reentrant Lock

以下示例说明了上述代码中 Reentrant Lock 的使用。我们创建了一个类 Thrd,在这个线程内部,我们定义了一个 fair value 为 true 的 ReentrantLock 对象。方法 operation() 将 tryLock() 方法的 Boolean 值存储到一个名为 lockAcquired 的变量中,该变量将检查锁是否被任何线程获取。如果锁被获取,则使用 lock() 方法将锁分配给该线程,然后线程开始执行给定的任务。任务将在 try 块中执行,并在 finally 块中使用 unlock() 方法释放锁。现在我们创建了三个线程类并调用 operation() 方法。在 main() 方法中,定义了三个线程类的对象,并调用它们的 start() 方法来启动线程执行。

Example.groovy

import java.util.concurrent.locks.ReentrantLock;

class Example {
   static void main(String[] args) {
     // 创建线程类的对象
     Thread1 oprt1 = new Thread1();
     Thread2 oprt2 = new Thread2();  
     Thread3 oprt3 = new Thread3();
     // 启动线程操作
     oprt1.start();
     oprt2.start();  
     oprt3.start();
   }
}

class Utility {
   // 创建 ReentrantLock 类的对象
   private static ReentrantLock lockr = new  ReentrantLock(true);
   static void operation(int data) {
     // 尝试获取锁
     boolean lockAcquired = lockr.tryLock(); 
     if (lockAcquired) {
       try {
         lockr.lock(); 
         // 将锁分配给线程
         for(int i = 1; i <= 4; i++) {
            println(data++);
         }
         // 检查锁计数
         println("Count of Lock: " + lockr.getHoldCount());
       } finally {
         lockr.unlock(); 
         // 释放锁 
       }
     } else {
       println("I am in else block");
     }
   }
}
class Thread1 extends Thread {
   // 线程编号 1 
   void run() {
      Utility.operation(1);
   }
}
class Thread2 extends Thread {
   // 线程编号 2 
   void run() {
      Utility.operation(5);
   }
}
class Thread3 extends Thread {
   // 线程编号 3
   void run() {
      Utility.operation(10);
   }
}

每次运行此程序都会产生不同的结果 −

输出

I am in else block
1
I am in else block
2
3
4
Count of Lock: 2