0

在我的 android 应用程序中,我的一个 MODEL 类中有一个特定的方法,并且该方法总是从 UI 线程以外的单独线程调用。

AlarmManger定期运行此方法,用户也可以选择从 UI 运行方法。(AlarmManger 操作和 UI 操作从主应用程序 UI 线程以外的单独线程调用此方法)。

我只是不想允许从 UI 和 AlarmManger 同时运行此方法。

当然我可以同步这个方法,保证一个线程执行一个方法。但这不是我想要的。

如果已经执行该方法,我想抛出一个异常并停止第二个线程(根据情况可能是 UI 调用或 AlarmManager)。因此,我可以通知用户操作已取消,因为找到了另一个正在运行的实例(AlarmManger 或表单 UI)。

我能问一下这种情况下最好的方法吗?谢谢

4

2 回答 2

1

我根据您的问题做出以下假设:

  1. 您想保证方法上的互斥,但如果存在争用,则返回(表示方法未执行),而不是阻塞线程。
  2. 您需要可重用模型类的实例(例如,假设一旦线程退出该方法,其他线程可以再次调用)

为此,最简单的选项可能是ReentrantLock::tryLock。像这样的东西(代码没有被编译或测试。)

class MyClass {
    private final ReentrantLock lock = new ReentrantLock();
    public void theMethod() {
        if(!lock.tryLock()) {
            throw new IllegalStateException("Running already");
        }
        try {
            // do stuff
        } finally {
            lock.unlock(); 
        }
    }
}

抛出异常表示方法正在执行意味着通过异常执行流控制,这不是好的做法。除非您有充分的理由保留例外,否则我建议您这样做:

class MyClass {
    private final ReentrantLock lock = new ReentrantLock();
    public boolean theMethod() {
        if(!lock.tryLock()) {
            return false;
        }
        try {
            doStuff();
        } finally {
            lock.unlock(); 
        }
        return true;
    }
}

返回值表明该方法是否可以运行,因此调用者可以做出相应的反应。

如果上面的 (2) 不适用(也就是说,您只想运行该方法一次并确保它不再被执行),那么您可以简单地执行以下操作:

class MyClass {
    private final AtomicBoolean hasExecuted = new AtomicBoolean(false);
    public boolean theMethod() {
        if(!hasExecuted.compareAndSet(false, true) {
            return false; // or throw an exception
        }
        doStuff();
        return true;
    }
}

我希望这会有所帮助。

于 2018-01-05T23:11:46.127 回答
0

为什么不使用信号量?你甚至可以使用Java 的

于 2018-01-02T17:20:19.523 回答