测试并发应用 (一)监控Lock接口

  1. 云栖社区>
  2. 博客>
  3. 正文

测试并发应用 (一)监控Lock接口

ali清英 2016-04-08 13:55:44 浏览642
展开阅读全文

声明:本文是《 Java 7 Concurrency Cookbook 》的第八章, 作者: Javier Fernández González 译者:郑玉婷  

校对:方腾飞

监控Lock接口

Lock 接口是Java 并发 API提供的最基本的机制来同步代码块。它允许定义临界区。临界区是代码块可以共享资源,但是不能被多个线程同时执行。此机制是通过Lock 接口和 ReentrantLock 类实现的。

在这个指南,你将学习从Lock对象可以获取的信息和如何获取这些信息。

准备

指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。

怎么做呢…

按照这些步骤来实现下面的例子:


001 package tool;
002  
003 import java.util.Collection;
004 import java.util.concurrent.TimeUnit;
005 import java.util.concurrent.locks.Lock;
006 import java.util.concurrent.locks.ReentrantLock;
007  
008 //1.   创建一个类,名为 MyLock ,扩展 ReentrantLock 类。
009 public class MyLock extends ReentrantLock {
010  
011     // 2. 实现 getOwnerName() 方法。此方法使用Lock类的保护方法 getOwner(), 返回控制锁的线程(如果存在)的名字。
012     public String getOwnerName() {
013         if (this.getOwner() == null) {
014             return "None";
015         }
016         return this.getOwner().getName();
017     }
018  
019     // 3. 实现 getThreads() 方法。此方法使用Lock类的保护方法 getQueuedThreads(),返回在锁里的线程的 queued
020     // list。
021     public Collection<Thread> getThreads() {
022         return this.getQueuedThreads();
023     }
024  
025     // 4. 创建一个类,名为 Task,实现 Runnable 接口.
026     public class Task implements Runnable {
027  
028         // 5. 声明一个私有 Lock 属性,名为 lock。
029         private Lock lock;
030  
031         // 6. 实现类的构造函数,初始化它的属性值。
032         public Task(Lock lock) {
033             this.lock = lock;
034         }
035  
036         // 7. 实现 run() 方法。创建迭代5次的for循环。
037         @Override
038         public void run() {
039             for (int i = 0; i < 5; i++) {
040  
041                 // 8. 使用lock()方法获取锁,并打印一条信息。
042                 lock.lock();
043                 System.out.printf("%s: Get the Lock.\n", Thread.currentThread()
044                         .getName());
045  
046                 // 9. 让线程休眠 500 毫秒。使用 unlock() 释放锁并打印一条信息。
047                 try {
048                     TimeUnit.MILLISECONDS.sleep(500);
049                     System.out.printf("%s: Free the Lock.\n", Thread
050                             .currentThread().getName());
051                 } catch (InterruptedException e) {
052                     e.printStackTrace();
053                 } finally {
054                     lock.unlock();
055                 }
056             }
057         }
058     }
059  
060     // 10. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。
061     public static void main(String[] args) throws Exception {
062  
063         // 11. 创建 MyLock 对象,名为 lock。
064         MyLock lock = new MyLock();
065  
066         // 12. 创建有5个Thread对象的 array。
067         Thread threads[] = new Thread[5];
068  
069         // 13. 创建并开始5个线程来执行5个Task对象。
070         for (int i = 0; i < 5; i++) {
071             Task task = lock.new Task(lock);
072             threads[i] = new Thread(task);
073             threads[i].start();
074         }
075  
076         // 14. 创建迭代15次的for循环。
077         for (int i = 0; i < 15; i++) {
078  
079             // 15. 把锁的拥有者的名字写入操控台。
080             System.out.printf("Main: Logging the Lock\n");
081             System.out.printf("************************\n");
082             System.out.printf("Lock: Owner : %s\n", lock.getOwnerName());
083  
084             // 16. 显示锁queued的线程的号码和名字。
085             System.out.printf("Lock: Queued Threads: %s\n",
086                     lock.hasQueuedThreads()); // 译者注:加上 System
087             if (lock.hasQueuedThreads()) {
088                 System.out.printf("Lock: Queue Length: %d\n",
089                         lock.getQueueLength());
090                 System.out.printf("Lock: Queued Threads: ");
091                 Collection<Thread> lockedThreads = lock.getThreads();
092                 for (Thread lockedThread : lockedThreads) {
093                     System.out.printf("%s ", lockedThread.getName());
094                 }
095                 System.out.printf("\n");
096             }
097  
098             // 17. 显示关于Lock对象的公平性和状态的信息。
099             System.out.printf("Lock: Fairness: %s\n", lock.isFair());
100             System.out.printf("Lock: Locked: %s\n", lock.isLocked());
101             System.out.printf("************************\n");
102  
103             // 18. 让线程休眠1秒,并合上类的循环。
104             TimeUnit.SECONDS.sleep(1);
105         }
106     }
107 }

它是如何工作的…

在这个指南里,你实现的MyLock类扩展了ReentrantLock类来返回信息,除此之外获得不到这些信息 ,因为ReentrantLock 类里的数据都是保护类型的。 通过MyLock类实现的方法:

  • getOwnerName():只有唯一一个线程可以执行被Lock对象保护的临界区。锁存储了正在执行临界区的线程。此线程会被ReentrantLock类的保护方法 getOwner()返回。 此方法使用 getOwner() 方法来返回线程的名字。
  • getThreads():当线程正在执行临界区时,其他线程尝试进入临界区就会被放到休眠状态一直到他们可以继续执行为止。ReentrantLock类保护方法getQueuedThreads() 返回 正在等待执行临界区的线程list。此方法返回 getQueuedThreads() 方法返回的结果。

我们还使用了 ReentrantLock 类里实现的其他方法:

  • hasQueuedThreads():此方法返回 Boolean 值表明是否有线程在等待获取此锁
  • getQueueLength(): 此方法返回等待获取此锁的线程数量
  • isLocked(): 此方法返回 Boolean 值表明此锁是否为某个线程所拥有
  • isFair(): 此方法返回 Boolean 值表明锁的 fair 模式是否被激活

更多…

ReentrantLock 类还有其他方法也是用来获取Lock对象的信息的:

  • getHoldCount(): 返回当前线程获取锁的次数
  • isHeldByCurrentThread(): 返回 Boolean 值,表明锁是否为当前线程所拥有

网友评论

登录后评论
0/500
评论
ali清英
+ 关注