0

场景如下。

我实现了这样的接口读取:

public interface MessageSourceProvider
{
    MessageSource getMessageSource(Locale locale);
}

这个接口有两种实现:一种从静态源中读取,在“构造函数时”完全初始化,另一种不;后一种实现是这样的(expiryEnabled是一个AtomicBoolean;评论被删除,完整的源代码在这里sources是一个Map<Locale, FutureTask<MessageSource>>):

@Override
public MessageSource getMessageSource(final Locale locale)
{
    if (!expiryEnabled.getAndSet(true))
        setupExpiry(expiryDuration, expiryUnit);

    FutureTask<MessageSource> task;

    synchronized (sources) {
        task = sources.get(locale);
        if (task == null || task.isCancelled()) {
            task = loadingTask(locale);
            sources.put(locale, task);
            service.execute(task);
        }
    }

    try {
        final MessageSource source = task.get(timeoutDuration, timeoutUnit);
        return source == null ? defaultSource : source;
    } catch (InterruptedException ignored) {
        Thread.currentThread().interrupt(); // <-- HERE
        return defaultSource;
    } catch (ExecutionException ignored) {
        return defaultSource;
    } catch (TimeoutException ignored) {
        task.cancel(true);
        return defaultSource;
    } catch (CancellationException ignored) {
        return defaultSource;
    }
}

由于接口本身没有声明抛出InterruptedException(因为某些实现永远不会这样做),所以我做Thread.currentThread.interrupt(). 我这样做是为了符合接口。反过来,这个接口的实现在“主”,面向用户的类中使用:

public String getMessage(final Locale locale, final String key)
{
    BUNDLE.checkNotNull(key, "query.nullKey");
    BUNDLE.checkNotNull(locale, "query.nullLocale");

    String ret;
    MessageSource source;

    for (final Locale l: LocaleUtils.getApplicable(locale))
        for (final MessageSourceProvider provider: providers) {
            source = provider.getMessageSource(l);
            if (source == null)
                continue;
            ret = source.getKey(key);
            if (ret != null)
                return ret;
        }

    // No source found which has the key... Return the key itself.
    return key;
}

现在,问题出在FutureTask. 就像.get()阻塞一样,InterruptedException可以抛出一个。并且由于基接口没有声明抛出异常,如果我捕捉到一个我选择恢复线程中断状态。

然而,文学不同意:它说你应该只这样做,或者忽略例外,只有当Thread你在你自己创造的范围内时。

我的问题是:这是一个面向用户的 API,我目前处理这个问题的方式是否存在潜在问题?如果是,我该如何解决?

4

2 回答 2

3

现在,问题出在 FutureTask 上。由于 .get() 是阻塞的,因此可以抛出 InterruptedException。并且由于基接口没有声明抛出异常,如果我捕捉到一个我选择恢复线程中断状态。

这是完全正确的。你应该总是那样做。

try {
    ...
} catch (InterruptedException e) {
    // InterruptedException clears interrupt flag
    // I always re-interrupt the thread first
    Thread.currentThread().interrupt();
    // then i decide if I want the thread to return or throw or ...
    return;
}

我还要说,您应该考虑中断线程意味着什么。有人中断了正在调用的线程future.get()。该线程应该如何响应?

  • 它应该抛出一个RuntimeException吗?
  • 它应该停止做它正在做的事情并退出吗?
  • 它应该关闭线程池吗?

然而,文献不同意:它说你应该只这样做,或者忽略例外,只有当你在你自己创建的线程中时。

我不确定您在看什么文献,但 IMO 不正确或不精确。

于 2013-06-19T19:32:06.837 回答
1

恢复中断标志是完全合法的,例如Java Concurrency in Practice中所讨论的。

于 2013-06-19T19:32:13.593 回答