的ReentrantReadWriteLock。读写获取优先级

时间:2014-04-16 08:32:01

标签: java multithreading concurrency locking reentrantreadwritelock

我研究ReentrantReadWriteLock

来自java doc的

片段:

  

线程在最旧之后才会获取读锁定   目前正在等待编写器线程已经获得并发布了写入   锁定

因此我理解。

阅读时间 - 1个时间单位

写入持续时间 - 3个时间单位

  1. 时间0 - 获取写锁定
  2. 时间1 - 读锁定尝试阅读
  3. 时间2 -         写锁定试写
  4. 因此,我希望遵循以下顺序:

    1. 首先写
    2. 第二次写
    3. 我的实验代码:

      public class RWLockCalculator {
          static long initTime = System.currentTimeMillis();
          private static int calculatedValue = 0;
          private static ReadWriteLock lock = new ReentrantReadWriteLock();
          public void calculate(int value) {
              lock.writeLock().lock();
              try {           
                  System.out.println("write lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
                  this.calculatedValue = 1;
                  Thread.sleep(300);
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              } finally {
                  lock.writeLock().unlock();
              }
          }
      
          public int getCalculatedValue() {
              lock.readLock().lock();
              try {           
                  System.out.println("read lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
                  Thread.sleep(100);
                  return calculatedValue;
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
                  return -1;
              } finally {
                  lock.readLock().unlock();
              }
          }
      }
      
      class Test {
          public static void main(String[] args) throws InterruptedException {
              new WriteThread().start();
              Thread.sleep(100);
              new ReadThread().start();
              Thread.sleep(100);
              new WriteThread().start();
      
          }
      }
      
      class ReadThread extends Thread {
          @Override
          public void run() {
              System.out.println(new RWLockCalculator().getCalculatedValue() + ", " + (System.currentTimeMillis() - RWLockCalculator.initTime));
          }
      }
      
      class WriteThread extends Thread {
          @Override
          public void run() {
              new RWLockCalculator().calculate(99);
              System.out.println("I have written in  " + (System.currentTimeMillis() - RWLockCalculator.initTime));
          }
      }
      

      出:

      write lock acquired at 0
      I have written in  300
      read lock acquired at 300
      1, 400
      write lock acquired at 400
      I have written in  700
      

      因此我得到了

      1. 首先写
      2. 阅读
      3. 第二次写
      4. 为什么我会得到这个结果?

        是否可以打破FIFO排序?

        更新

        请比较java doc中的两个兄弟片段(关于公平模式):

        第一

        尝试获取公平读锁定(非重复读取)的线程将阻止是否保持写入锁定,或者是否存在等待写入器线程。在最旧的当前等待的写入器线程获取并释放写锁定之前,线程将不会获取读锁定。当然,如果等待的写入者放弃等待,将一个或多个读取器线程保留为队列中最长的服务器并且写锁定空闲,则将为这些读取器分配读锁定。

        第二

        尝试获取公平写锁定(非重复)的线程将阻塞,除非读取锁定和写入锁定都是空闲的(这意味着没有等待的线程)。 (请注意,非阻塞ReentrantReadWriteLock.ReadLock.tryLock()和ReentrantReadWriteLock.WriteLock.tryLock()方法不遵循此公平设置,并且如果可能,将获取锁定,无论等待线程如何。) < / p>

        我不完全理解那里写的内容的含义但是我看到ReentrantReadWriteLock使用不同的政治来获取读锁和写锁。我建议如果java doc中的政治相同则不会写两个缩进。

        ReadLock可以共享锁。这只是一个区别吗?

1 个答案:

答案 0 :(得分:3)

首先,应以公平模式创建ReentrantReadWriteLock以强制执行特定的锁定获取顺序:

private static ReadWriteLock lock = new ReentrantReadWriteLock(true);

然后,javadoc非常清楚地描述了你的情况:

  

当构造为公平时,线程使用近似到达顺序策略争用进入。当释放当前保持的锁定时,将为最长等待的单个写入器线程分配写入锁定,或者如果有一组读取器线程等待的时间超过所有等待的写入器线程,则将为该组分配读取锁定。

由于您的阅读器线程等待的时间比第二个写入器线程长,因此它会在编写器线程之前获取锁定。