Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Collection.size() to replace the counter in this code?

Here's the code:

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

It's a snippet from the book Java Concurrency in Practice, and I'm thinking about that maybe the counter reservations is unnecessary as we could simply use queue.size() to get the number of elements in queue.

Am I right?

like image 954
user2916610 Avatar asked Nov 23 '15 05:11

user2916610


1 Answers

No, that would create a deadlock actually.

You would need to synchronize put and take if you want to use size in a parallel fashion. But take is blocking and you would now have a blocking take call synchronized on the same object as the put call. take can't take until something is put. put can't put until take gives up the lock. That's a deadlock.

like image 182
djechlin Avatar answered Nov 14 '22 23:11

djechlin