在Java中实现互斥锁

3
我有一个多线程应用程序(确切地说是Tomcat中的Web应用程序)。在其中,几乎每个线程都会拥有自己的实例。在该类中,有一段代码在一个方法中只能由一个线程(用户)执行。我的研究表明,我需要的是互斥锁(它似乎是一个计数为1的信号量)。
因此,在进一步研究后,我认为我应该采取以下措施。重要的是要注意我的锁对象是静态的。
我做得正确吗?
public Class MyClass {
  private static Object lock = new Object();
  public void myMethod() {
    // Stuff that multiple threads can execute simultaneously.
    synchronized(MyClass.lock) {
      // Stuff that only one thread may execute at a time.
    }
  }
}

2
没有理由它不能工作。你也可以使用一个ReentrantLock来达到同样的效果。 - fge
3个回答

5

在您的代码中,myMethod 可能在任何线程中执行,但是一次只能在一个线程中执行。这意味着永远不会有两个线程同时执行此方法。我认为这就是您想要的 - 所以:是的。


谢谢!线程会“排队”等待获取锁吗?如果无法获取锁,它们不会立即失败吗? - John Fitzpatrick
1
是的,它们会等待。如果该方法永远不返回,它们甚至可能无限挂起并冻结应用程序。 - Yogu
1
为了避免程序挂起,你可能需要考虑使用Futures模式/框架,或者采用某种形式的回调系统。这将允许那些等待的人“拿一张票,在等待时做其他事情”。 - Dan Hardiker
@brainzzy 根据JVM实现,这些阻塞线程是使用睡眠锁还是自旋锁(忙等待)来阻塞的? - overexchange

2

通常,多线程问题来自于可变性——当两个或更多线程访问同一数据结构并且其中一个或多个线程对其进行修改时。

第一反应是使用锁定控制访问顺序,就像你所建议的那样——但是你可能很快就会陷入锁争用的困境中,在这种情况下,由于线程在锁监视器上停止,你的应用程序将损失大量处理时间。

你可以通过使用不可变数据结构来消除大部分问题。因此,从setter返回一个新对象,而不是修改现有对象,并利用并发集合,如ConcurrentHashMap / CopyOnWriteArrayList。

并发编程是你需要理解的内容,特别是在今天的现代计算世界中,吞吐量来自并行化。


谢谢。在这种情况下,我保护的不是数据,而是对一个外部硬件资源的访问,该资源一次只允许一个“用户”。我同意,并发编程是必不可少的,我计划提高自己在这方面的技能。 - John Fitzpatrick
有效观点 - 尽管我仍然会谨慎考虑这种瓶颈可能对系统产生的影响。我大部分时间都在调整高负载/吞吐量应用程序。 - Dan Hardiker

1

这将允许一个线程一次通过该块。其他线程将等待,但没有队列,不能保证线程能够公平地获取锁。实际上,使用偏向锁,它不太可能是公平的。 ;)

如果有任何原因无法使您的锁为final,那么很可能是一个错误。顺便说一下:您可能可以改用synchronized(MyClass.class)


MyClass.class 可供其他类使用,因此可能成为一个潜在的缺陷来源。 - Yogu
谢谢。在这种情况下,我可以接受不公平的待遇。该应用程序使用非常少,而且他们是被困的观众(即没有其他应用程序与我的竞争)。 - John Fitzpatrick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接