我可以使用Collection.size()替换此代码中的计数器吗?

时间:2015-11-23 05:38:10

标签: java multithreading concurrency

以下是代码:

public class LogService {
    private final BlockingQueue<String> queue;
    private final LoggerThread loggerThread;
    private final PrintWriter writer;
    @GuardedBy("this") private boolean isShutdown;
    @GuardedBy("this") private int reservations;    //  <-- counter
    public void start() { loggerThread.start(); }
    public void stop() {
        synchronized (this) { isShutdown = true; }
        loggerThread.interrupt();
    }
    public void log(String msg) throws InterruptedException {
        synchronized (this) {
            if (isShutdown)
                throw new IllegalStateException(...);
            ++reservations;
        }
        queue.put(msg);
    }
    private class LoggerThread extends Thread {
        public void run() {
            try {
                while (true) {
                    try {
                        synchronized (LogService.this) {
                            if (isShutdown && reservations == 0)
                                break;
                        }
                        String msg = queue.take();
                        synchronized (LogService.this) {
                            --reservations;
                        }
                        writer.println(msg);
                    } catch (InterruptedException e) { /* retry */ }
                }
            } finally {
                writer.close();
            }
        }
    }
}

它是 Java Concurrency in Practice 这本书的摘录,我想到的可能是计数器reservations是不必要的,因为我们可以简单地使用{{ 1}}获取queue.size()中的元素数量。

我是对的吗?

1 个答案:

答案 0 :(得分:5)

不,这会造成实际的死锁。

如果您想以并行方式使用put,则需要同步takesize。但take正在屏蔽,您现在可以在与take调用相同的对象上同步阻止put调用。 take只有put才能使用put。在take放弃锁定之前, for(i=0;i<=50;i++) if(i%10==4) { printf("%d",i); } 无法放置。那是一个僵局。