开发者

(How) can I possibly "miss a signal" with this ConcurrentLinkedQueue and sleep()?

In my Java application, several threads put data in a queue from which another thread (just one) takes objects and dispatches them.

Occasionally, the consuming thread seems to not notice that new items have been added to the queue, as the log messages indicating a poll cease to appear. Log messages from the producing threads indicate that these items do indeed arrive. Googling some taught me that this seems to be known as "missed signal". Since I'm neither waiting nor using locks, I'm not sure if this applies to me.

What really puzzles me is that when I interrupt the consumer thread, it processes all items in the queue and then stays silent again, without ever exiting.

Here's the main loop of the consumer thread, the producer threads do stuff like reading from sockets and their only common thing is that they use add() on the queue from which the consumer is polling.

public class FieldFrontService
{
    // ...

    private ConcurrentLinkedQueue<Transmission> _qRec;

    // ...

    private Runnable _createReceptionist()
    {
        return new Runnable() {
            @Override
            public void run()
            {
                while (!Thread.currentThread().isInterrupted()) 开发者_运维百科{
                    Transmission tx = FieldFrontService.this._qRec.poll();
                    if (null == tx) {
                        try {
                            Thread.sleep(250);
                        } catch (InterruptedException e) {
                            break;
                        }
                    } else {
                        FieldFrontService.this._receiveTransmission(tx);
                    }
                }
            }
        }

    // ...
}


Perhaps you are better off using an ExecutorService which combines a Thread pool and a Queue. Also it works. ;)

public class FieldFrontService {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    void receiveTransmission(final Transmission tx) {
        executor.execute(new Runnable() {
            public void run() {
                FieldFrontService.this._receiveTransmission(tx);
            }
        });
    }
}


I think your InterruptedException is getting eaten somewhere in your call stack.

This pattern is what concerns me:

try {                             
    Thread.sleep(250);
} catch (InterruptedException e) {
    break;
} 

If you are using a similar pattern in your code, that the thread interrupted state was lost. For example, if Thread.interrupted() were used in your call stack, that will reset the interrupted status of your thread. As a result, your while loop will never exit: the status was reset to false.

These two lines are the points of concern:

Transmission tx = FieldFrontService.this._qRec.poll();
// ....
FieldFrontService.this._receiveTransmission(tx); 

If either of those calls makes a call to Thread.currentThread().interrupted(), you will lose the isInterrupted boolean. I would look over the implementation of both of those methods in case the Exception / state is being consumed.

My handling of InterruptedExceptions is different. I prefer to rethrow the interrupt:

try {                             
    Thread.sleep(250);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} 

That way, I ensure that there is no possibility that my interrupt was lost. Basically, I'm trying to say, no, seriously, STOP Thread STOP!


Is it not because the break statement exits the while loop, causing the thread to stop? What happens if you remove the break statement? Or is that what you expect?

I'm suggesting the thread doesn't see the new items, because the thread has already stopped due to an exception you didn't expect.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜