gpt4 book ai didi

java - Java 同步(锁定、条件)的奇怪行为

转载 作者:行者123 更新时间:2023-11-30 04:25:01 24 4
gpt4 key购买 nike

我只是想模拟一个简单的读者/作者场景。

这是代码:

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

我真的不明白这是怎么发生的......这只是控制台打印混淆了还是我真的在这里遗漏了一些东西?

最佳答案

我相信您的问题与这几行有关,对吗?

Reader 9 reading (1 readers)
Reader 8 reading (3 readers)
Reader 5 reading (2 readers)

您预计它是 1,2 个读者,然后是 3 个读者。

简而言之,问题是因为您的打印不是同步块(synchronized block)的一部分。

根据您的代码给出可能原因的示例,如下:

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

不难想象为什么这个数字看起来很奇怪。

将系统 out 语句放在锁定范围内,就在 readerCount++ 之后,将给出预期的结果。

关于java - Java 同步(锁定、条件)的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16141526/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com