6

GoogleGuavaとして実装したいサービスがありますService

このサービスは基本的に、while (true)イベントがに到着したときにイベントを処理するループを実行しますBlockingQueue。簡略化されたサンプルコードはこちらから入手できます。

https://gist.github.com/3354249

問題は、コードがでブロックすることBlockingQueue#take()です。そのため、サービスを停止する唯一の方法は、そのスレッドを中断することです。これはGuavaを使用して可能AbstractExecutionThreadServiceですか?

もちろん、この場合は、queue.take()を使用してポーリングループに置き換えることができるためqueue.poll(1, TimeUnit.SECONDS)、スレッドを中断する必要がなくなります。でも:

  • パフォーマンスとコードの可読性の両方の理由から、これは避けたいと思います。

  • スレッドの中断を回避できない場合もあります。たとえば、からバイトを読み取っているときにサービスがブロックされた場合などInputStreamです。

4

2 に答える 2

7

メソッドをオーバーライドexecutor()して独自のエグゼキュータを提供すると、スレッドへの参照がフィールドに保存されます。その後、必要に応じて、スレッドを簡単に中断できます。

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;

import com.google.common.util.concurrent.AbstractExecutionThreadService;

public abstract class InterruptibleExecutionThreadService extends AbstractExecutionThreadService {
    private final AtomicReference<Thread> runningThread = new AtomicReference<Thread>(null);

    @Override
    protected Executor executor() {
        return new Executor() {
            @Override
            public void execute(Runnable command) {
                Thread thread = Executors.defaultThreadFactory().newThread(command);
                runningThread.compareAndSet(null, thread);

                try {
                    thread.setName(serviceName());
                } catch (SecurityException e) {
                    // OK if we can't set the name in this environment.
                }
                thread.start();
            }
        };
    }

    protected void interruptRunningThread() {
        Thread thread = runningThread.get();
        if (thread != null) {
            thread.interrupt();
        }
    }
}
于 2012-12-21T13:15:17.860 に答える
4

AbstractExecutionThreadServiceを呼び出すためにスレッドへの参照を取得する方法が実際にはないため、スレッドを中断することは実際にはオプションではないと思いますinterrupt()

BlockingQueueを使用している場合は、サービスがまだ実行されているかどうかを確認するwhileループ内でポーリングするか、番兵の値を使用してワーカーメソッドに停止する必要があることを警告できます。

例:

ポーリング:

while(isRunning()) {
    Value v = queue.poll(1, TimeUnit.SECONDS);
    // do something with v
}

番兵:

while(isRunning()) {
    Value v = queue.take();
    if(v == POISON) {
        break;
    }
    // do something with v
}

私は個人的にポーリングソリューションを試して、パフォーマンスがどのようなものかを確認しました。それが実際にパフォーマンスに与える影響が非常に少ないことに驚かれるかもしれません。

InputStreamからの読み取りに関しては、InputStreamが長寿命であり、無期限にブロックされる可能性がある場合、を使用することAbstractExecutionThreadServiceは実際には可能ではないと思います。代わりに、メソッドAbstractServiceで中断できるように、独自の実行スレッドへの参照を作成して保持するanを使用する必要があります。doStop()

于 2012-08-15T04:25:36.193 に答える