我只是想模拟一个简单的读者/作家场景。
以下是代码:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReadersWriters implements Solution {
private final static Lock readerLock = new ReentrantLock();
private final static Lock writerLock = new ReentrantLock();
private final static Condition noReader = readerLock.newCondition();
private static CountDownLatch countDown;
private static volatile int readerCount=0;
public static class Reader implements Runnable {
private static int count=1;
private int id = count++;
@Override
public void run() {
int readCount = (int) (Math.random()*20);
while (readCount > 0) {
readCount--;
writerLock.lock();
try {
readerLock.lock();
try {
readerCount++;
} finally {
readerLock.unlock();
}
} finally {
writerLock.unlock();
}
System.out.println("Reader "+id+" reading ("+readerCount+" readers)");
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Reader "+id+" done");
readerLock.lock();
try {
readerCount--;
noReader.signalAll();
} finally {
readerLock.unlock();
}
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
countDown.countDown();
}
}
public static class Writer implements Runnable {
private static int count=1;
private int id = count++;
@Override
public void run() {
int writeCount = (int) (Math.random()*20);
while (writeCount>0) {
writeCount--;
writerLock.lock();
try {
readerLock.lock();
try {
while (readerCount>0) {
noReader.await();
}
System.out.println("Writer "+id+" writing");
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Writer "+id+" done");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readerLock.unlock();
}
} finally {
writerLock.unlock();
}
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
countDown.countDown();
}
}
public static void main(String []args) {
Executor exec = Executors.newCachedThreadPool();
int numReaders = 10;
int numWriters = 4;
countDown = new CountDownLatch(numReaders+numWriters);
for (int i=0; i<numReaders; i++) {
exec.execute(new Reader());
}
for (int i=0; i<numWriters; i++) {
exec.execute(new Writer());
}
try {
countDown.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我知道我也可以使用ReadWriteLock
,但那不是重点......
我的问题是在日志中,我看到这样的事情:
Writer 4 writing
Writer 4 done
Reader 9 reading (1 readers)
Reader 8 reading (3 readers)
Reader 5 reading (2 readers)
Reader 8 done
Reader 5 done
Reader 9 done
Writer 3 writing
Writer 3 done
而且我真的不明白这是怎么发生的......难道只是控制台打印混乱或我真的在这里缺少什么?
答案 0 :(得分:1)
您在阅读器中的System.out.println
次呼叫未同步。究竟是什么让你担心呢?
答案 1 :(得分:1)
我相信你的问题是关于这几行的吗?
Reader 9 reading (1 readers)
Reader 8 reading (3 readers)
Reader 5 reading (2 readers)
你希望它是1,2,然后是3个读者。
简而言之,问题是因为您的打印不是同步块的一部分。
根据您的代码举例说明可能的原因,这里是:
writerLock.lock();
try {
readerLock.lock();
try {
readerCount++;
} finally {
readerLock.unlock();
}
} finally {
writerLock.unlock();
}
System.out.println("Reader "+id+" reading ("+readerCount+" readers)");
对于上面的代码,简而言之,readerCount
的更新由writerLock
保护。但是有可能:
READER8 READER5
(readerCount = 1 at this point)
lock writerLock
readerCount++ (=2)
unlock writerLock
lock writerLock
update readerCount to 3
unlock writerLock
sysout of readerCount (3)
lock writerLock
readerCount-- (=2)
sysout of readerCount (2)
unlock writerLock
lock writerLock
readerCount-- (=1)
unlock writerLock
不难想象为什么这个数字看起来很奇怪。
将系统输出语句置于锁定范围内,就在readerCount ++之后,将给出预期的结果。