多线程锁定方法

时间:2011-07-07 06:15:07

标签: java multithreading

Ex 1)

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}

Ex 2)

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

我从java网站获得了这两个java代码,但我没有清楚地看到这两个代码之间的区别。你们可以给出更多解释,我应该互换使用哪种情况?提前致谢

2 个答案:

答案 0 :(得分:2)

有两点不同:

  • 第一个示例锁定this而不是私有引用。我认为这通常是一个坏主意 - 这意味着其他代码也可以同时锁定在同一个监视器上,这使得更难以推理您的代码。除非您希望其他代码能够在同一台监视器上获取锁定(在这种情况下,我通常会为此目的明确地公开监视器 ),为什么要放置自己在其他代码的摆布?在大多数情况下,锁应该是一个实现细节,但是将其作为公共引用(this有效)使得该实现细节对全世界可见。
  • 第二个示例显示同一类中的两个方法锁定不同的引用。这意味着两个线程可以同时调用inc1inc2。如果第一个示例中有多个方法,所有锁定都在this上,那么一次只有一个线程可以输入这些方法的任何

我通常对单个类中的所有内容使用单个锁,除非我有充分的理由相信会有很多独立操作仅处理该类的部分状态 - 在这种情况下,这表明课程可能太大而无法开始。

我也将我的“锁定变量”设为最终版本,因为您几乎永远希望能够在对象的生命周期内更改它们。

所以,如果我真的想要使用锁,我可能最终将第二个例子写成:

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private final Object lock = new Object();

    public void inc1() {
        synchronized(lock) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock) {
            c2++;
        }
    }
}

但是,我考虑:

  • 不以实例方法线程安全开始。我发现同时从多个线程中使用一个类的单个实例是相对罕见的。 (静态方法通常应该是线程安全的。)
  • 使用AtomicLong代替锁定。通常使用更高级别的概念而不是线程原语可以使您的代码更容易理解更高效。

答案 1 :(得分:0)

在第一个示例中,您正在同步this对象(实际的类对象。在大多数情况下,这已经足够了,请将其视为粗粒锁。

在第二个示例中,您锁定创建的对象,其唯一目的是锁定。这种方法允许你对锁定进行更细粒度的控制(在这种情况下,有两个锁同时进行,类对象不会被锁定)

此外,如果您synchronize方法,它与在this对象上进行同步几乎相同。基本上它们是可以互换的,但您可能更喜欢根据您的情况使用锁定控制。