我有一个同步练习,我需要同步一个read方法,这样任何数量的线程都可以执行它,只要没有执行写方法。这必须从头开始,所以我不能使用java.util.concurrent.locks等。
为此我需要某种机制来保护,但不阻止读取方法,因此读取线程被写入阻止,而不是被其他读取阻塞。我不能使用普通的锁,因为在read方法中调用lock方法会导致其他读线程等待。
规则应如下: 当一个线程在write()内部时,没有其他线程必须输入read()或write() 当一个线程在read()内部时,没有其他线程必须输入write(),但是它们可以输入read()
我已经尝试构建一些自制锁来解决这个问题。 WriteLock是一个相当标准的reenterant锁,除了它正在执行读取时阻塞(使用readcounter) 如果遍历write(),则ReadLock应该只导致线程等待。否则它应该只允许线程进行其业务并增加WriteLocks计数器。
代码:
package sync;
public class SyncTest {
Long testlong = new Long(0L);
int reads = 0;
int writes = 0;
WriteLock w = new WriteLock();
ReadLock r = new ReadLock(w);
public SyncTest() {
// TODO Auto-generated constructor stub
}
public static void main(String args[]){
final SyncTest s = new SyncTest();
for(int i = 0 ; i<3 ; i++){ //Start a number of threads to attack SyncTest
final int ifinal = i;
new Thread(){
int inc = ifinal;
@Override
public void run() {
System.out.println("Starting "+inc);
long starttime = System.currentTimeMillis();
try {
while(System.currentTimeMillis()-starttime < 10){
if (inc < 2){
s.readLong();
}else{
s.writeLong(inc+1);
}
}
System.out.println(inc + " done");
if(inc == 0){
Thread.sleep(1000);
System.out.println(s.reads+" "+s.writes);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Thread "+inc+" "+super.toString();
}
}.start();
}
}
public Long readLong() throws InterruptedException{
Long l;
r.lock(); //Lock for reading
//System.out.println("Read "+reads);
l = testlong;
reads++;
r.unlock(); //Unlock after reading
return l;
}
public void writeLong(int i) throws InterruptedException{
w.lock(); //Lock for writing
//System.out.println("Write "+writes);
int curreads = reads;
int curwrites = writes;
testlong = testlong + i;
writes++;
Thread.sleep(100); //Simulate long write
if(curreads != reads){
System.out.println("Reads did not lock");
}
if(curwrites+1 != writes){
System.out.println("Writes did not lock");
}
w.unlock(); //Unlock writing
}
protected class WriteLock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
int readers = 0; //The number of readers currently through the reading lock.
public synchronized void lock() throws InterruptedException {
System.out.println("Locking: "+Thread.currentThread());
Thread callingThread = Thread.currentThread();
while ((isLocked && lockedBy != callingThread) || readers > 0) { //Wait if locked or readers are in read()
wait();
}
isLocked = true;
lockedCount++;
lockedBy = callingThread;
System.out.println("Is locked: "+Thread.currentThread());
}
public synchronized void unlock() {
//System.out.println("Unlocking: "+Thread.currentThread());
if (Thread.currentThread() == this.lockedBy) {
lockedCount--;
if (lockedCount == 0) {
System.out.println("Is unlocked: "+Thread.currentThread());
isLocked = false;
notify();
}
}
}
}
protected class ReadLock{
WriteLock lock;
public ReadLock(WriteLock lock) {
super();
this.lock = lock;
}
public synchronized void lock() throws InterruptedException { //If write() then wait
System.out.println("Waiting to read: "+Thread.currentThread());
Thread callingThread = Thread.currentThread();
while (lock.isLocked && lock.lockedBy != callingThread) {
wait();
}
lock.readers++; //Increment writelocks readers
System.out.println("Reading: "+Thread.currentThread());
}
public synchronized void unlock() {
lock.readers--; //Subtract from writelocks readers
notify();
}
}
}
这不起作用,但是读取锁定工作到目前为止它在线程写入时锁定读取器,但是在WriteLock解锁时它不会释放它们,据我所知。
这听起来不是概念上的,或者是否有一些我不了解的显示器?或其他什么?
答案 0 :(得分:14)
(在问题被编辑之前回答了它是一个练习。)
听起来你想要ReadWriteLock
实现。
ReadWriteLock维护一对关联的锁,一个用于只读操作,另一个用于写入。只要没有写入器,读锁定可以由多个读取器线程同时保持。写锁是独占的。
一个实现是ReentrantReadWriteLock
。
特别是对于并发性,在尝试实现自己的代码之前,总是值得查看现有的库(java.util.concurrent
等)。如果你和我一样,即使你能在并发方面使它正确,它也不会像专家写的代码那样高效......当然,这一切都是有效的。从;)
答案 1 :(得分:1)
您的ReadLock和WriteLock正在同步不同的对象,并在不同的对象上调用wait和notify。
这允许ReadLock在WriteLock验证时修改WriteLock中的计数。它还会导致不同的锁不会从等待的调用中唤醒。
如果您修改您的ReadLock以使用WriteLock作为监视器,您将获得更好的结果(我没有检查这是否是唯一的问题)
protected class ReadLock{
WriteLock lock;
public ReadLock(WriteLock lock) {
super();
this.lock = lock;
}
public void lock() throws InterruptedException { //If write() then wait
synchronized (lock) {
System.out.println("Waiting to read: "+Thread.currentThread());
Thread callingThread = Thread.currentThread();
while (lock.isLocked && lock.lockedBy != callingThread) {
lock.wait();
}
lock.readers++; //Increment writelocks readers
System.out.println("Reading: "+Thread.currentThread());
}
}
public void unlock() {
synchronized (lock) {
lock.readers--; //Subtract from writelocks readers
lock.notify();
}
}
}