Java 如果检测到互斥,则停止当前线程

Java 如果检测到互斥,则停止当前线程,java,android,multithreading,java-threads,android-thread,Java,Android,Multithreading,Java Threads,Android Thread,在我的android应用程序中,我的一个模型类中有一个特定的方法,该方法总是从一个单独的线程(而不是UI线程)调用 AlarmManger定期运行此方法,用户还可以选择从UI运行此方法。(AlarmManger操作和UI操作从主应用程序UI线程以外的单独线程调用此方法) 我只是不想允许从UI和AlarmManger同时运行此方法 当然,我可以同步这个方法,这保证了一次只能执行一个线程。但那不是我想要的 我想抛出一个异常并停止第二个线程(可能是UI调用或AlarmManager,具体取决于情况),

在我的android应用程序中,我的一个模型类中有一个特定的方法,该方法总是从一个单独的线程(而不是UI线程)调用

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

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

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

我想抛出一个异常并停止第二个线程(可能是UI调用或AlarmManager,具体取决于情况),如果其中一个线程已经在执行该方法。所以我可以通知用户,当发现另一个正在运行的实例(AlarmManger或表单UI)时,操作被取消


我想问一下,在这种情况下,最好的解决办法是什么。谢谢你为什么不用信号灯呢?您甚至可以使用

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

  • 您希望保证方法上的互斥,但如果存在争用,则只返回(表示方法未执行),而不阻塞线程
  • 您需要模型类的实例可重用(例如,假设一旦一个线程退出该方法,其他线程就可以再次调用)
  • 为此,最简单的选择可能是。类似这样的内容(代码未编译或测试)

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

    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;
        }
    }
    

    我希望这会有所帮助。

    也许在线程之间共享一个
    AtomicBoolean
    。如果其中一个线程已经将该值更改为true,那么另一个线程将立即结束,而不执行任何操作。可能有一个UI的侦听器,因此如果另一个线程正在运行,那么按钮将暂时禁用。
    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;
        }
    }