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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With