6

シリアルイベントが発生するのを待つ際にタイムアウトが発生する未来を計算しています:

Future<Response> future = executor.submit(new CommunicationTask(this, request));
response = new Response("timeout");
try {
  response = future.get(timeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (InterruptedException | TimeoutException e) {
  future.cancel(true);
  log.info("Execution time out." + e);
} catch (ExecutionException e) {
  future.cancel(true);
  log.error("Encountered problem communicating with device: " + e);
}

このCommunicationTaskクラスはObserver、シリアル ポートからの変更をリッスンするインターフェイスを実装しています。

問題は、シリアル ポートからの読み取りが比較的遅く、シリアル イベントが発生している場合でも時間がなくなり、 aTimeoutExceptionがスローされることです。シリアル イベントが発生しているときに、未来のタイムアウト クロックを停止するにはどうすればよいですか?

で試してみましたAtomicReferenceが、何も変わりませんでした:

public class CommunicationTask implements Callable<Response>, Observer {
  private AtomicReference atomicResponse = new AtomicReference(new Response("timeout"));
  private CountDownLatch latch = new CountDownLatch(1);
  private SerialPort port;

  CommunicationTask(SerialCommunicator communicator, Request request) {
    this.communicator = communicator;
    this.message = request.serialize();
    this.port = communicator.getPort();
  }

  @Override
  public Response call() throws Exception {
    return query(message);
  }

  public Response query(String message) {
    communicator.getListener().addObserver(this);
    message = message + "\r\n";
    try {
      port.writeString(message);
    } catch (Exception e) {
      log.warn("Could not write to port: " + e);
      communicator.disconnect();
    }
    try {
      latch.await();
    } catch (InterruptedException e) {
      log.info("Execution time out.");
    }
    communicator.getListener().deleteObserver(this);
    return (Response)atomicResponse.get();
  }

  @Override
  public void update(Observable o, Object arg) {
    atomicResponse.set((Response)arg);
    latch.countDown();
  }
}

この問題を解決するにはどうすればよいですか?

編集:

OK、1つのエラーがありました。atomicResponse関数で を設定する前に、ラッチをカウントダウンしていましたupdate。今はうまくいっているように見えますが、このアプローチが正しい方法であるかどうかという疑問はまだありますか?

4

2 に答える 2

0

これが役立つことを願っています。コードからすべてが明らかであることを期待して、これについてはコメントしません。

class CommunicationTask implements Callable<String>, Observer {
    volatile boolean ignoreTimeoutException;

    public CommunicationTask(SerialCommunicator communicator, Request request) {
    }

    public String call() throws Exception {
        Thread.sleep(1000);
        return "done";
    }

    public void update(Observable o, Object arg) {
        ignoreTimeoutException = true;
    }
}

class FutureCommunicationTask extends FutureTask<String> {
    private CommunicationTask ct;

    public FutureCommunicationTask(CommunicationTask ct) {
        super(ct);
        this.ct = ct;
    }

    public String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        try {
            return super.get(timeout, unit);
        } catch (TimeoutException e) {
            if (ct.ignoreTimeoutException) {
                return get();  //  no timeout wait 
            }
            throw e;
        }
    }
}

public class Test {

    public static void main(String[] args) throws Exception {
        CommunicationTask ct = new CommunicationTask(null, null);
        FutureTask<String> fct = new FutureCommunicationTask(ct);
        ExecutorService ex = Executors.newSingleThreadExecutor();
        ex.execute(fct);
//      uncomment this line and timeout will be cancelled 
        ct.update(null, null);  
        String res = fct.get(1, TimeUnit.MILLISECONDS);
        System.out.println(res);
    }
}
于 2012-12-03T16:08:25.047 に答える