First of all to prevent mark question as duplicate by guys who don't like read to the end I have read Producer-Consumer Logging service with Unreliable way to shutdown question. But it is not fully answer the question and answer contradicts the book text.
In book provided following code:
public class LogWriter {
private final BlockingQueue<String> queue;
private final LoggerThread logger;
private static final int CAPACITY = 1000;
public LogWriter(Writer writer) {
this.queue = new LinkedBlockingQueue<String>(CAPACITY);
this.logger = new LoggerThread(writer);
}
public void start() {
logger.start();
}
public void log(String msg) throws InterruptedException {
queue.put(msg);
}
private class LoggerThread extends Thread {
private final PrintWriter writer;
public LoggerThread(Writer writer) {
this.writer = new PrintWriter(writer, true); // autoflush
}
public void run() {
try {
while (true)
writer.println(queue.take());
} catch (InterruptedException ignored) {
} finally {
writer.close();
}
}
}
}
Now we should to understand how to stop this process. We should stop logging but should not skip already commited messages.
Author researches approach:
public void log(String msg) throws InterruptedException {
if(!shutdownRequested)
queue.put(msg);
else
throw new IllegalArgumentException("logger is shut down");
}
and comment it like this:
Another approach to shutting down LogWriter would be to set a “shutdown requested” flag to prevent further messages from being submitted, as shown in Listing 7.14. The con- sumer could then drain the queue upon being notified that shutdown has been requested, writing out any pending messages and unblocking any producers blocked in log . However, this approach has race conditions that make it unreliable. The implementation of log is a check-then-act sequence: producers could observe that the service has not yet been shut down but still queue messages after the shutdown, again with the risk that the producer might get blocked in log and never become unblocked. There are tricks that reduce the likelihood of this (like having the consumer wait several seconds before declaring the queue drained), but these do not change the fundamental problem, merely the likelihood that it will cause a fail- ure.
The phrase build enough hard for me.
I understand that
if(!shutdownRequested)
queue.put(msg);
is not atomic and message can be added to the queue after shutdowning. Yes, it is not very accurate but I don't see problem. queue just will be drain and when queue will be empty we can stop LoggerThread. Especially I don't understand why producers can be blocked.
Author didn't provide full code thus I cannot understand all details. I believe that this book was read by community majority and this example has detailed explanation.
Please explain with full code example.