【问题标题】:Java, Make a method that can only be called once at a timeJava,制作一次只能调用一次的方法
【发布时间】:2014-04-24 18:13:21
【问题描述】:

我有一个应用程序,它使用读写锁来防止在调用所谓的“重新连接”方法时运行其他方法。现在,我希望这个“重新连接”方法一次只被调用一次。例如,当 Thread1 调用“reconnect”,而“reconnect”正在执行时,Thread2 调用它,它要么立即返回,要么等待 Thread1 的调用完成然后返回。 (导致只执行一次)。正如您可能想象的那样,我有一个与某些 API 交互的应用程序,当我的会话超时时,它需要重新连接,但我不希望每个线程都创建一个新连接,因为这完全没有必要。我希望我提供了足够的信息。

【问题讨论】:

标签: java multithreading locking


【解决方案1】:

最好维护一个锁对象并在其上进行同步,例如:

public class MyClass {

    private final Object lock = new Object();

    public void reconnect() {
        synchronized(lock) {
            ....
        }
    }

    ....
}

原因是当您在方法签名中使用 synchronized 关键字时,实际上是在您的 MyClass 实例上进行同步。问题是,您班级之外的任何其他代码也可以做到这一点。例如,

public class SomeOtherClass {
    public void go(final MyClass myClass) {
        synchronized(myClass) {
            wait(Integer.MAXIMUM_VALUE);
        }
    }
}

现在,如果其他线程想要调用myClass.reconnect(),他们就不能,因为SomeOtherClass 已经锁定了myClass 实例。

【讨论】:

  • 挖掘 Java 最黑暗角落之一的方法,哈哈。在其他类的类定义上同步是一种可怕的做法,但你是非常正确的。
  • 它总是偶然发生,如果有人试图破坏你的代码,这是一个不错的攻击媒介。
  • 请注意,我已经在相关类中集成了一个 ReentrantReadWriteLock。 tryLock 会和你的解决方案一样工作吗?我仅将写入部分用于重新连接。其余使用连接的方法,使用 read.lock() 和 read.unlock();
  • 是的,使用读写锁显然比同步更好。
  • 非常感谢您的大力帮助。我会尽快接受这个答案。
【解决方案2】:

Synchronized 关键字防止多个线程同时执行函数。然后你只需要在你的方法中检查连接的状态。

public synchronized void reconnect() {
    if (!connection.isActive()) { // this method will depend on what type of connection you have
        // your code ...
    }
}

如果连接已经处于活动状态,基本上你只需要 reconnect() 成为一个空操作。

【讨论】:

  • 谢谢,没想到答案这么简单 :)
  • 当您有多个函数作用于需要一起同步的单个资源时,它会变得更加棘手,但这是简单的情况。干杯!
  • 我想我会使用你的 connection.isActive 想法和 tryLock。我认为这在这种情况下效果最好。
【解决方案3】:

我可能不会使用直接锁。

我将只使用一个线程来处理所有连接/重新连接操作并将请求对象排队。这有点复杂,但是:

  • 它更灵活,因为这样的机制将允许两者 同步和异步请求/回复。

  • 调试更容易,因为连接/重新连接只会发生 在一个线程上串行。

  • 如果有的话,很容易添加一个额外的连接到 [whatever] 要求或可接受。

  • 可以检测超时、保持活动和连接问题,并且 记录/纠正,即使没有未完成的请求。

  • 对可能会阻塞的操作进行简单的硬锁 延长时间太令人担忧了。

也许只有我……:)

【讨论】:

    【解决方案4】:

    你需要一个标志和同步:

    private boolean mReconnectNeeded;
    
    public synchronized void reconnectIfNeeded() {
        if (mReconnectNeeded) {
            mReconnectNeeded = false;
            // reconnect; if it fails, set the flag again
        }
    }
    
    public synchronized void setReconnectNeeded() {
        mReconnectNeeded = true;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 2019-09-24
      • 2011-12-17
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 1970-01-01
      相关资源
      最近更新 更多