Producer-Consumer Logging service with Unreliable way to shutdown - java

I'm reading 'Java Concurrency in Practice', one example sort of makes me confused, it's about producer-consumer logging service:
public class LogWriter {
private final BlockingQueue<String> queue;
private final LoggerThread logger;
private boolean shutdownRequested = false;
public LogWriter(Writer writer) {
this.queue = new LinkedBlockingQueue<String>(CAPACITY);
this.logger = new LoggerThread(writer);
}
public void start() { logger.start(); }
public void shutdownlog() { shutdownRequested = true; }
public void log(String msg) throws InterruptedException {
if (!shutdownRequested)
queue.put(msg);
else
throw new IllegalStateException("logger is shut down");
}
private class LoggerThread extends Thread {
private final PrintWriter writer;
...
public void run() {
try {
while (true)
writer.println(queue.take());
} catch(InterruptedException ignored) {
} finally {
writer.close();
}
}
}
}
From the book, it's unreliable if we would shutdown it. It wrote:
Another approach to shutting down LogWriter would be to set a "shutdown requested" flag to prevent further messages from being submitted,as shown in Listing7.14.The consumer 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 checkthenact 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 failure.
I don't quite understand it. does it mean that another thread happens to run into queue.put(msg) right after the shutdownflag set to true?
Thanks, guys.

The loophole is between the producer checking the flag by checking shutdownRequested and then putting the message in the queue. If shutdown happens and the worker stops performing in this tiny timespan, this happens.
Although its unlikely, it might happen that you enqueue messages when flag is already set.
But I cant see that the producer getting blocked, because the worker simply ignores the shutdown flag.
If the producer tries to enqueue a message while the queue is full it blocks, but becomes unblocked when the worker takes elements from the queue.

Related

Understanding shutdown requested flag when shutting down

I'm reading B. Goetz JCIP and come across some misunderstanding in the section 7.2 about cancellin Thread-based services. Here's the code:
public class LogWriter{
private final BlockingQueue<String> queue;
private final LoggerThread logger;
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 void run() {
try{
while(true)
writer.println(queue.take());
} catch(InterruptedException ignored){
} finally {
writer.close();
}
}
}
He said that such service does not provide a way to terminate it. He gives another alternative to it:
public void log(String msg) throws InterruptedException {
if(!shutdownRequested)
queue.put(msg);
else
throw new IllegalArgumentException("logger is shut down");
}
Now he says that
The implementation of log is chek-than-act sequnce: 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 unlocked.
The emphasized is not clear to me.
If the consumer drained the queue to some collection it will make any producers blocked in log() unlocked. Even if some producer try to put a log message to the queue, it won't be blocked. The only thing that I see is this message won't be logged since the queue has been drained.
QUESTION: Why does he says that producers mught be blocked and never unlocked. What did I miss?
If you look at BlockingQueue doc you can see:
A Queue that additionally supports operations that wait for the queue
to become non-empty when retrieving an element, and wait for space to
become available in the queue when storing an element.
I.e. producer may be blocked if there is no more space left in the queue: if the service has been shut down the queue is not drained anymore.
Since the code is incomplete it's hard to say what the author intended. Presumably the logger thread also checks shutdownRequested to stop logging:
public void run() {
try{
while(shutdownRequested)
writer.println(queue.take());
} catch(InterruptedException ignored){
} finally {
writer.close();
}
}
If you write this, consider a scenario where the shutdown is requested when the queue is full and there are threads blocked on queue.put: the logger thread stops calling queue.take and these threads stay blocked forever.
Even if that was not the case, there is a race condition with the variable shutdownRequested. A thread may request shutdown between the variable is read and the message is queued in the log method, so that messages still get queued after shutdown was requested.

producer-consumer using arraydeque working only in breakpoint

I am implementing a producer and consumer pattern using ArrayDeque and running into a strange problem.
Consumer.java
Class Consumer {
public final Queue<Msg> my_queue = new ArrayDeque<Msg>();
public void begin() {
new Thread() {
new Runnable() {
public void run() {
while(true) {
while(my_queue.isEmpty()) {
// do nothing
}
Msg msg = my_queue.remove();
msg.doSomething();
}
}
}
}.start();
}
}
Since my_queue is public, I may have > 1 threads performing my_queue.add(msg). However, the strangeness occurs because doSomething is never called when running in production. However, when i am in debug mode and use a break point, doSomething() will be called! Can anyone explain this?
ArrayDeque is not thread safe. You'll have to guard it with a lock (synchronized keyword or read/write lock) in order to access it safely from different threads.
Another option is to use a thread safe deque implementation, preferably a blocking one (e.g. LinkedBlockingDeque), which will also allow you to avoid your busy wait for the queue to become non-empty.

How to Keep Listener Thread Alive

I have a class which is a listener for incoming messages and should be alive forever (So that it can listen for incoming messages) until i explicitly disconnect the connection for it. I have declared the thread as setDaemon(false) but it terminates with the calling methods termination.
Please tell me how to keep that thread alive and also please throw some light on how to implement the Spring TaskExecutor to achieve same.
Thanks in advance.
it is a listener it gets notified when someone sends message... so how do i keep it running ?
The Listener Class
public class MyListnerImpl implements Listener {
private final connectionImpl con;
public MyListnerImpl(ConnectionImpl con) {
if (con.isAuthenticated() && con.isConnected()) {
if (logger.isInfoEnabled()) {
logger.info("Initializing XmppListner:");
}
this.itsCon = con;
Thread t1 = new Thread(this);
t1.setDaemon(false);
t1.start();
}
}
public final void listnerInterfaceMethod(final Chat chat, final Message message) {
System.out.println("Message" + message);
}
public final void run() {
itsCon.getChatManager().addChatListener(new ChatManagerListener() {
public void chatCreated(final Chat chat, final boolean createdLocally) {
if (!createdLocally) {
chat.addMessageListener(itsFbml);
}
}
});
}
}
Calling class simply creates its object and thread gets started by the Listeners constructor.
I want to keep this thread created run until i interrupt it.
There are a few things you could do that would be better than hanging the initial thread forever:
Use otherThread.join(). This will cause the current thread you are running in to sleep until the other thread has finished executing.
As #nanda suggests, use ExcecutorService.shutdown() to wait until a pool of threads has finished.
Use otherThread.setDaemon(false) and simply let your initial thread exit. This will set your new threads as user threads. Java will not shut down until the only threads running are daemon threads.
synchronized(this) {
while (true) {
this.wait();
}
}
This will make the current thread wait on the monitor of the current class until someone calls notify(), or forever.
copied from How do you hang a thread in Java in one line?
A thread says alive until run() returns (or throw an error/exception) If you want to keep it alive, use a loop, don't return and catch any error/exception.
This is how i solved the problems that time,
So this case was not of multi threading , had just a single thread which needed to run for ever,
So Inserted
public final void run() {
while(true)
{
//Run Method Logic...
}
}
And instantiated it from a spring bean.
I was also looking at more fancy things for this single threaded scenario like awaitTermination(); or something like that.

Producer Consumer in Java

I've written the following code, but I feel I'm going wrong somewhere:
public class ProcessQueue {
static BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
public ProcessQueue() {
process();
}
public void add(String message) throws InterruptedException {
System.out.println("Added Queue size:" + queue.size());
System.out.println("Locked by Producer");
queue.put(message);
System.out.println("Lock Released by Producer");
}
public static void process() {
new Thread() {
#Override
public void run() {
try {
while (true) {
System.out.println("Locked by Consumer");
Message.send(queue.take());
System.out.println("Locked Released by Consumer");
System.out.println("Consuming Queue size:" + queue.size());
}
} catch (Exception ex) {
System.out.print(ex.getMessage());
}
}
}.start();
}
}
Here add(String) adds the string to the queue. It is called whenever it receives an input from a UDP port. process() processes the queue and sends it for processing to the class Message. The output Locked and Released Print Statements is not in the desired order.
EDIT
My expected answer should be:
if it's in Producer that is add then Locked by Producer -> then add to Queue -> Lock Release. same way would be in consumer. But the operations shouldn't interleave i.e. once locked by producer is printed it shouldn't print locked by consumer and then release locks.
The only time blocking will occur here is on take when the queue is empty. Otherwise puts will continue to happen. So you may see the queue's size not increment by one. You may want to put a bound on the LinkedBlockingQueue. Fyi the LBQ is default unbounded
Edit based on your edit:
My answer thus far is explaining what you are seeing and why. You are looking for a synchronous messaging passing queue. You can do this with the following:
new SynchrnousQueue();
new LinkedBlockingQueue(1);
new ArrayBlockingQueue(1);
new TransferQueue();
SynchrnousQueue does exactly what you want. The Linked&ArrayBlockingQueue with a bound of 1 pretty much does the same. TransferQueue is a new queue offered in Java 7 which has transfer methods that wait until a thread is ready to acquire.

Blocking queue and multi-threaded consumer, how to know when to stop

I have a single thread producer which creates some task objects which are then added into an ArrayBlockingQueue (which is of fixed size).
I also start a multi-threaded consumer. This is build as a fixed thread pool (Executors.newFixedThreadPool(threadCount);). I then submit some ConsumerWorker intances to this threadPool, each ConsumerWorker having a refference to the above mentioned ArrayBlockingQueue instance.
Each such Worker will do a take() on the queue and deal with the task.
My issue is, what's the best way to have a Worker know when there won't be any more work to be done. In other words, how do I tell the Workers that the producer has finished adding to the queue, and from this point on, each worker should stop when he sees that the Queue is empty.
What I've got now is a setup where my Producer is initialized with a callback which is triggered when he finishes it's job (of adding stuff to the queue). I also keep a list of all the ConsumerWorkers I've created and submitted to the ThreadPool. When the Producer Callback tells me that the producer is done, I can tell this to each of the workers. At this point they should simply keep checking if the queue is not empty, and when it becomes empty they should stop, thus allowing me to gracefully shutDown the ExecutorService thread pool. It's something like this
public class ConsumerWorker implements Runnable{
private BlockingQueue<Produced> inputQueue;
private volatile boolean isRunning = true;
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(isRunning || !inputQueue.isEmpty()) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Object queueElement = inputQueue.take();
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
}
The problem here is that I have an obvious race condition where sometimes the producer will finish, signal it, and the ConsumerWorkers will stop BEFORE consuming everything in the queue.
My question is what's the best way to synchronize this so that it all works ok? Should I synchronize the whole part where it checks if the producer is running plus if the queue is empty plus take something from the queue in one block (on the queue object)? Should I just synchronize the update of the isRunning boolean on the ConsumerWorker instance? Any other suggestion?
UPDATE, HERE'S THE WORKING IMPLEMENTATION THAT I'VE ENDED UP USING:
public class ConsumerWorker implements Runnable{
private BlockingQueue<Produced> inputQueue;
private final static Produced POISON = new Produced(-1);
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(true) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Produced queueElement = inputQueue.take();
Thread.sleep(new Random().nextInt(100));
if(queueElement==POISON) {
break;
}
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Consumer "+Thread.currentThread().getName()+" END");
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void stopRunning() {
try {
inputQueue.put(POISON);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This was inspired heavily by JohnVint's answer below, with only some minor modifications.
=== Update due to #vendhan's comment.
Thank you for your obeservation. You are right, the first snippet of code in this question has (amongst other issues) the one where the while(isRunning || !inputQueue.isEmpty()) doesn't really make sense.
In my actual final implementation of this, I do something which is closer to your suggestion of replacing "||" (or) with "&&" (and), in the sense that each worker (consumer) now only checks if the element he's got from the list is a poison pill, and if so stops (so theoretically we can say that the worker has to be running AND the queue must not be empty).
You should continue to take() from the queue. You can use a poison pill to tell the worker to stop. For example:
private final Object POISON_PILL = new Object();
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(isRunning) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Object queueElement = inputQueue.take();
if(queueElement == POISON_PILL) {
inputQueue.add(POISON_PILL);//notify other threads to stop
return;
}
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void finish() {
//you can also clear here if you wanted
isRunning = false;
inputQueue.add(POISON_PILL);
}
I'd send the workers a special work packet to signal that they should shut down:
public class ConsumerWorker implements Runnable{
private static final Produced DONE = new Produced();
private BlockingQueue<Produced> inputQueue;
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
for (;;) {
try {
Produced item = inputQueue.take();
if (item == DONE) {
inputQueue.add(item); // keep in the queue so all workers stop
break;
}
// process `item`
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
To stop the workers, simply add ConsumerWorker.DONE to the queue.
In your code-block where you attempt to retrive element from the queue , use poll(time,unit) instead of the take().
try {
Object queueElement = inputQueue.poll(timeout,unit);
//process queueElement
} catch (InterruptedException e) {
if(!isRunning && queue.isEmpty())
return ;
}
By specifying appropriate values of timeout , you ensure that threads wont keep blocking in case there is a unfortunate sequence of
isRunning is true
Queue becomes empty , so threads enter blocked wait ( if using take()
isRunning is set to false
Can not we do it using a CountDownLatch, where the size is the number of records in the producer. And every consumer will countDown after process a record. And its crosses the awaits() method when all tasks finished. Then stop all ur consumers. As all records are processed.
There are a number of strategies you could use, but one simple one is to have a subclass of task that signals the end of the job. The producer doesn't send this signal directly. Instead, it enqueues an instance of this task subclass. When one of your consumers pulls off this task and executes it, that causes the signal to be sent.
I had to use a multi-threaded producer and a multi-threaded consumer.
I ended up with a Scheduler -- N Producers -- M Consumers scheme, each two communicate via a queue (two queues total). The Scheduler fills the first queue with requests to produce data, and then fills it with N "poison pills". There is a counter of active producers (atomic int), and the last producer that receives the last poison pill sends M poison pills to the consumer queue.

Categories

Resources