简体   繁体   English

Java同步的奇怪行为(锁定,条件)

[英]Strange behavior with Java Synchronization (Lock, Condition)

I am just trying to model a simple readers / writers scenario. 我只是想为一个简单的读者/作家场景建模。

Here is the code: 这是代码:

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();
        }
    }
}

I know I could also use ReadWriteLock , but that's not the point... 我知道我也可以使用ReadWriteLock ,但这不是重点...

My problem is that in the log, I see things like this: 我的问题是在日志中,我看到这样的事情:

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

And I really don't see how this could happen... Is it just console prints that are getting mixed up or I am really missing something here? 而且我真的不知道这怎么可能...是只是控制台打印变得混乱,还是我在这里真的缺少什么?

Your System.out.println calls in the Reader aren't synchronised. 阅读器中的System.out.println调用不同步。 What, exactly, worries you here? 到底是什么让您担心?

I believe your problem is about these few lines right? 我相信您的问题与这几行有关吗?

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

which you expect it to be 1,2 and then 3 readers. 您希望它是1,2,然后是3个读者。

In brief, the problem is because your printing is not part of the synchronization block. 简而言之,问题是因为您的打印不属于同步块。

To give an example of possible cause base on your code, here it is: 在您的代码的基础上给出一个可能的原因示例,这里是:

writerLock.lock();
try {
    readerLock.lock();
    try {
        readerCount++;
    } finally {
        readerLock.unlock();
    }
} finally {
    writerLock.unlock();
}
System.out.println("Reader "+id+" reading ("+readerCount+" readers)");

for the above piece of code, in brief, update of readerCount is guarded by writerLock . 用于上述代码段,在短暂的更新readerCount由把守writerLock However it is possible that: 但是有可能:

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

Not hard to imagine why the number looks strange. 不难想象为什么这个数字看起来很奇怪。

Put the system out statement in the locked scope, just after readerCount++, will give u result expected. 将system out语句放在readerScope ++之后的锁定范围内,将给您预期的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM