Java不公平的ReentrantReadWriteLock如何真正起作用?

时间:2019-04-19 15:49:26

标签: java multithreading

我已使用ReentrantReadWriteLock用Java编写了以下测试代码,以了解公平和非公平模式之间的区别。但是,我看到两种模式下的结果和输出总是相同的。似乎它总是在公平模式下工作。有人能解释在哪种情况下公平和不公平的模式会导致不同的行为吗?

    def __init__(self):
        pass               #use only if you want an empty constructor

输出始终为:

package lockTest;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class MyLockTest {
    static private ReadWriteLock myLock = new ReentrantReadWriteLock(false);

    public class Reader extends Thread {
        int val_;
        public Reader(int val) {
            val_ = val;
        }
        public void run() {
            if (val_ > 0) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            myLock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + ": Reader inside critical section - val: " + val_ + "-----");
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            myLock.readLock().unlock();
        }
    }

    public class Writer extends Thread {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            myLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + ": Writer inside critical section *****");
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            myLock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        MyLockTest test1 = new MyLockTest();
        MyLockTest.Reader reader1 = test1.new Reader(0);
        MyLockTest.Writer writer1 = test1.new Writer();
        MyLockTest.Reader reader2 = test1.new Reader(1);

        reader2.start();
        writer1.start();
        reader1.start();
    }
}

当我将“锁定创建”更改为“公平”模式时,上面的输出是我期望看到的:

Thread-0: Reader inside critical section - val: 0-----
Thread-1: Writer inside critical section *****
Thread-2: Reader inside critical section - val: 1-----

对于非公平模式,我希望看到以下输出:

static private ReadWriteLock myLock = new ReentrantReadWriteLock(true);

1 个答案:

答案 0 :(得分:2)

使用“公平”与“不公平”模式会影响在争用情况下如何将锁分配给线程。

对于ReentrantReadWriteLock,使用Javadoc:使用“不公平”模式,未指定读写锁的输入顺序,而使用“公平”模式, 线程使用近似到达顺序策略争用进入。


我们可以看到使用公平/非公平如何通过在同一锁上争用一些线程来影响程序执行;参见下面的程序。

运行示例代码,一个ReentrantWriteLock由不同的线程竞争;经过1000次锁定操作后,我们转储每个线程获得锁定的次数。

在使用USE_FAIR=false的情况下,计数是随机的,可能的输出是:

Thread thread-B finished, count=920
Thread thread-A finished, count=79
Thread thread-D finished, count=0
Thread thread-C finished, count=0

在使用USE_FAIR=true的情况下,输出始终像

Thread thread-D finished, count=249
Thread thread-A finished, count=250
Thread thread-C finished, count=250
Thread thread-B finished, count=250

示例代码

package sample1;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class UseLock {

  public static void main(String[] args) {
    UseLock o = new UseLock();
    o.go();
  }

  private void go() {
    TotalPermits tp = new TotalPermits();

    tp.lock.writeLock().lock();

    Contender a = new Contender(tp, "thread-A");
    Contender b = new Contender(tp, "thread-B");
    Contender c = new Contender(tp, "thread-C");
    Contender d = new Contender(tp, "thread-D");

    a.start();
    b.start();
    c.start();
    d.start();

    tp.lock.writeLock().unlock();
  }
}

class TotalPermits {
  private static final boolean USE_FAIR = true;

  private int count = 1_000;
  ReentrantReadWriteLock lock = new ReentrantReadWriteLock(USE_FAIR);

  public boolean get() {
    try {
      lock.writeLock().lock();
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) { }
      return --count>0;
    } finally {
      lock.writeLock().unlock();
    }
  }
}

class Contender extends Thread {
  private int count = 0;
  final String name;
  final TotalPermits tp;

  Contender(TotalPermits tp, String name) {
    this.tp = tp;
    this.name = name;
  }

  @Override
  public void run() {
    while ( tp.get() ) {
      count++;
    }
    System.out.printf("Thread %s finished, count=%d%n", name, count);
  }
}

注意:

上面的示例代码使用“写”锁,一次只能由一个线程持有。因此,我们可以使用它在竞争者之间划分N个许可。另一方面,只要没有线程持有写锁,“读取”锁可以由多个线程持有。