Java方法同步使用不当?

时间:2013-11-01 14:57:28

标签: java multithreading synchronization

假设有以下代码:

class MyClass {
    synchronized void myMethod1() {
        //code 
    }

    synchronized void myMethod2() {
        //code
    }
}

现在假设myMethod1()myMethod2()访问不同的数据;现在如果有两个线程,则线程A只调用myMethod1()而线程B只调用myMethod2()

如果线程A正在执行myMethod1(),那么线程B阻塞等待myMethod2(),即使它们没有访问相同的数据,也没有理由这样做?据我所知,synchronized方法使用this对象的监视器实例方法和MyClass.class对象的静态函数监视器。

5 个答案:

答案 0 :(得分:3)

您对情况的理解是正确的。

典型的解决方案是为相关资源分别设置专用lock objects

class MyClass {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    void myMethod1() {          
      lock1.lock();

      try {
        //code 
      } finally {
        lock1.unlock();
      }            
    }

    void myMethod2() {
      lock2.lock();

      try {
        //code 
      } finally {
        lock2.unlock();
      }    
    }
}

答案 1 :(得分:1)

你的所有假设都是正确的。在没有数据共同的情况下,没有理由在方法级别进行同步。

答案 2 :(得分:1)

sychronized方法将锁定对象本身。因此,每个方法都必须等待另一个方法完成其释放对象的访问权限。如果您的方法真正访问不同的数据,您可以执行以下操作:

class MyClass {
    private static Object mLock1 = new Object();
    private static Object mLock2 = new Object();

    void myMethod1() {
        synchronized(mLock1) {
            //code 
        }
    }

    void myMethod2() {
        synchronized(mLock2) {
            //code 
        }
    }
}

然后您可以独立访问它们。

编辑:您基本上可以将同步方法视为与此等效:

void myMethod1() {
    synchronized(this) {
        //your code
    }
}

如上所示,很清楚为什么两个同步方法相互阻塞,因为它们必须等待this上的锁定才能释放。

答案 3 :(得分:0)

是的,将这两种方法声明为synchronized将使它们相互阻塞,即使它们访问不同的数据元素。

为避免这种情况,您可以使用更细粒度的锁。 E.g:

class MyClass {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    void myMethod1() {
        synchronized (lock1) {
            //code 
        }
    }

    void myMethod2() {
        synchronized (lock2) {
            //code 
        }
}

答案 4 :(得分:0)

您可以对myMethod1myMethod2使用不同的监视器,如下所示:

class MyClass {
    Object monitor1 = new Object();
    Object monitor2 = new Object();
    void myMethod1() {
        synchornized(monitor1) {
        //code 
        }
    }

    void myMethod2() {
        synchronized(monitor2) {
        //code
        }
    }
}