在Java中同步方法的正确方法

时间:2014-12-09 11:03:14

标签: java multithreading synchronized

我有一个示例类:

public class LocksAndSynchronization {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    static int count;

    public void methodOne() {

        for (int i = 1; i <= 10000; i++) {
            count++;
        }

    }

    public void methodTwo() {

        for (int i = 1; i <= 10000; i++) {
            count++;
        }

    }

    public synchronized void process() {
        methodOne();
        methodTwo();
    }

    public static void main(String[] args) throws InterruptedException {
        final LocksAndSynchronization l = new LocksAndSynchronization();
        Thread t1 = new Thread() {

            @Override
            public void run() {
                l.process();
            }

        };

        Thread t2 = new Thread() {

            @Override
            public void run() {
                l.process();
            }

        };


        t1.start();
        t2.start();

        t1.join();
        t2.join();


        System.out.println("count: " + count);

    }

}

process()实际上调用了这两个方法。那么这是一种更好的方法呢?

  1. 同步methodOnemethodTwo
  2. 同步process()(如上面的代码所示)?
  3. 以上两个选项都可行。但是哪一个更有意义?

6 个答案:

答案 0 :(得分:3)

count是静态的,因此对于所有对象都是相同的。所以你需要同步进程静态方式。要做到这一点,创建一个静态锁并使用它

static Object staticObject = new Object();
public void process() {
   synchronized( staticObject){
      methodOne();
      methodTwo();
   }
}

或者你可以同步methodOne和methodTwo

static Object staticObject = new Object();
public void methodOne() {
    synchronized( staticObject){
      for (int i = 1; i <= 10000; i++) {
          count++;
      }
    }
}

public void methodTwo() {
    synchronized( staticObject){
      for (int i = 1; i <= 10000; i++) {
          count++;
      }
    }
}

此外,在函数声明中使用synchronize关键字,意味着将对象本身用作锁。所以,如果你有多个对象,你的块就会根据对象进行同步。

答案 1 :(得分:2)

我更愿意同步methodOnemethodTwo,因为可以从对象外部调用它们。它们也可以在不嵌入process的情况下调用。因此,每个方法都应该以线程安全的方式实现。

希望有所帮助。

答案 2 :(得分:2)

您的简化代码无法轻易辨别问题的本质。例如,count是静态的,因此在实例级别锁定不起作用,但这可能只是一个干扰器。

更重要的考虑因素是methodOnemethodTwo两个公共方法,它们显然需要同步,但不能单独执行。如果您选择仅同步process方法,则意味着您要求methodOnemethodTwo的所有其他呼叫者也要正确处理同步,这看起来非常不稳定设计。

此外,如果您不需要整个process是原子的,并且它可以分解为两个单独的原子步骤,那么再次锁定遵循这些语义更自然。这取决于您是否要从程序中的其他位置调用methodOnemethodTwo

答案 3 :(得分:1)

建议尽可能少地同步代码,因为它会产生争用(其他线程在等待)。因此,方法1是优选的。

答案 4 :(得分:0)

无论您是单独同步process还是任何方法,您仍然不会在method1和method2之间保持一致(即在这些调用之间不会更改变量count)。原因是变量count是静态的,所以它不是线程安全的,即使它是在synchronized方法中使用的。

答案 5 :(得分:0)

正如Adem所说,静态计数&#39;字段需要静态锁定。然而,这里有更大的界面设计问题。 methodOnemethodTwo都是 public ,这意味着可以从任何其他类调用它们。如果要求它们在同步上下文中执行,那么建议它们都使用同步机制。

如果不是methodOnemethodTwo是公开的,我的偏好是在更高级别执行同步化(因为这稍微更有效和灵活),即在process方法,然后对另外两个方法发表评论,这两个方法指定必须从同步上下文中调用它们。