我已使用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);
答案 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个许可。另一方面,只要没有线程持有写锁,“读取”锁可以由多个线程持有。