java - 防止并发方法执行

标签 java multithreading concurrency

我有一门课有 start()stop()方法并希望执行以下操作:
1 不能在另一个方法运行时调用其中一个方法,例如当start()然后调用 stop()不能同时调用。
2a 对已经运行的任一方法的调用应立即跳过,
2b 或者它们应该在初始调用(拥有锁)返回的同时返回。
我认为第一个要求可以通过添加 synchronized 来实现堵塞。要求 2a 可能非常适合 AtomicBoolean .然而,对我来说,这看起来比它应该的要复杂。还有其他可能性吗?是否有可能一次性满足这两个要求的类(class)?
真的不知道如何实现2b。
当我重新阅读我的示例代码时,我意识到 synchronized可能需要在 isStarted 之前查看。但是,当调用已经在方法中时,我无法立即返回。
另一方面,使用下面给出的代码,我无法阻止一个线程比较并设置 isStartedtrue然后被挂起,stop() 中的另一个线程尽管 start() 执行停止逻辑逻辑还没有完成。
示例代码


    private final AtomicBoolean isStarted = new AtomicBoolean(false);
    private final Object lock = new Object();

    public void start() {
        if (isStarted.compareAndSet(false, true)) {
            synchronized(lock) {
                // start logic
            }
        } else {
            log.warn("Ignored attempt to start()");
        }
    }

    public void stop() {
        if (isStarted.compareAndSet(true, false)) {
            synchronized(lock) {
                // stop logic
            }
        } else {
            log.warn("Ignored attempt to stop()");
        }        
    }

最佳答案

让我们想象一下这个场景:

  • 线程 A 进入“开始”。
  • 线程 A 很忙,试图挖掘“开始”逻辑。这需要一段时间。
  • 虽然 A 仍然很忙,因此您的代码的状态是“开始进行中”,但还不是“我已经开始”,线程 B 也调用 start。

  • 你说的是B马上回来你没问题。
    我怀疑你是否真的是那个意思;这意味着 B 中的代码调用“开始”,然后此调用返回,但对象尚未处于“开始”状态。当然,您打算仅在对象实际处于“运行”状态时才对 start() 的调用正常返回,如果不可能,则通过异常返回。
    鉴于我正确解释了您的需求,请忘记 boolean 值;您只需要同步即可。请记住,锁是您的 API 的一部分,并且我们在 java 中通常没有公共(public)字段,因此您不应该有公共(public)锁,除非您大量记录(并考虑您的代码与锁交互的方式作为在不破坏向后兼容性的情况下您无法修改的公共(public) API - 通常不是您想要随便分发的 promise ,因为这对于 future 的更新来说是一副手铐),因此,您创建私有(private)锁定字段的想法很棒。但是,我们已经有一个私有(private)的唯一实例,我们可以将其重新用于锁:
        private final AtomicBoolean isStarted = new AtomicBoolean(false);
    
        public void start() {
            synchronized (isStarted) {
                if (isStarted.compareAndSet(false, true)) startLogic();
            }
        }
    
        public void stop() {
            synchronized (isStarted) {
                if (isStarted.compareAndSet(true, false)) stopLogic();
            }
        }
    
        public boolean isStarted() {
            return isStarted.get();
        }
    
        private void startLogic() { ... }
        private void stopLogic() { ... }
    }
    
    此代码将确保调用 'start();'将保证代码在正常返回时处于“已启动”状态,或者至少是这样(一个异常(exception)是,如果其他线程正在等待停止它并在线程启动后立即停止;大概,很奇怪也就是说,无论哪种状态导致 stop() 运行都希望发生这种情况)。
    此外,如果您希望锁定行为成为此类 API 的一部分,您可以这样做。例如,您可以添加:
    /** Runs the provided runnable such that the service is running throughout.
     * Will start the service if neccessary and will block attempts to stop
     * the service whilst running. Restores the state afterwards.
     */
    public void run(Runnable r) {
        synchronized (isStarted) {
            boolean targetState = isStarted.get();
            start(); // this is no problem; locks are re-entrant in java.
            r.run();
            if (!targetState) stop();
        }
    }
    

    关于java - 防止并发方法执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64858546/

    相关文章:

    java - 使用类加载器 AntClassLoader[] 找不到 ant taskdef 类

    c++ - 信号唤醒线程

    java - 对于大于堆的基于 JVM 的队列存在哪些解决方案?

    java - 我如何在 Slick2D/LWJGL 或一般游戏编程中使用 "delta"?

    java - Camel : Mock and return value from component in route

    java - "Synchronized"后面发生了什么?

    c# - 用锁包装任务不是很有用吗?

    java - Java中的构造函数同步

    java - 如何在ReentrantLock锁定的临界区中等待指定时间?

    java - 在等待 api 调用完成时并行调用 N 阻塞 api 调用以充分利用 CPU 的最佳方法是什么?