如果我在同一个类上同步了两个方法,它们能同时在同一个对象上运行吗?例如:

class A {
    public synchronized void methodA() {
        //method A
    }

    public synchronized void methodB() {
        // method B
    }
}

我知道我不能在两个不同的线程中对同一个对象运行methodA()两次。在methodB()中也是如此。

但我可以运行methodB()在不同的线程,而methodA()仍在运行?(同一对象)


当前回答

不容易理解的同步的关键思想是,它只有在对同一个对象实例调用方法时才会起作用——这已经在回答和评论中突出显示了——

下面的示例程序是清楚地查明相同的-

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

请注意,如果在不同的对象实例上调用方法,则输出中允许同时访问的方式是不同的。

输出带有noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects()注释-输出是in order methodA in > methodA Out ..methodB in > methodB Out

和输出synchronizedEffectiveAsMethodsCalledOnSameObject()注释- 输出显示在突出显示的部分-中,Thread1和Thread0同时访问方法da

增加线程数将使其更加明显。

其他回答

不,这是不可能的,如果这是可能的,那么这两个方法可以同时更新同一个变量,这很容易破坏数据。

将您的代码想像如下所示:

class A {

public void methodA() {
    synchronized(this){        
      //method A body
    }
}

public void methodB() {
    synchronized(this){
      // method B body
    }
}

因此,在方法级别上同步仅仅意味着同步(这个)。 如果任何线程运行该类的方法,它将在开始执行之前获得锁,并持有它直到方法执行完成。

但是我可以在不同的线程上运行methodB()而methodA()仍然是 跑步吗?(同一对象)

的确,这是不可能的!

因此,多个线程将不能同时在同一个对象上运行任意数量的同步方法。

不容易理解的同步的关键思想是,它只有在对同一个对象实例调用方法时才会起作用——这已经在回答和评论中突出显示了——

下面的示例程序是清楚地查明相同的-

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

请注意,如果在不同的对象实例上调用方法,则输出中允许同时访问的方式是不同的。

输出带有noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects()注释-输出是in order methodA in > methodA Out ..methodB in > methodB Out

和输出synchronizedEffectiveAsMethodsCalledOnSameObject()注释- 输出显示在突出显示的部分-中,Thread1和Thread0同时访问方法da

增加线程数将使其更加明显。

清楚地说,静态同步和非静态同步方法都可能同时或并发地运行,因为一个有对象级锁,另一个有类级锁。

从oracle文档链接

使方法同步有两个效果:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object. Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads

这将回答您的问题:在同一个对象上,当第一个同步方法正在执行时,您不能调用第二个同步方法。

看看这个文档页,了解内在锁和锁的行为。