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

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

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

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

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


这两种方法都锁定同一个监视器。因此,你不能同时从不同的线程在同一个对象上执行它们(两个方法中的一个会阻塞,直到另一个方法完成)。


你同步的是对象而不是类。所以它们不能同时在同一物体上运行


在示例中,methodA和methodB是实例方法(与静态方法相反)。将synchronized放在实例方法上意味着线程必须在线程开始执行该方法中的任何代码之前获得调用该方法的对象实例上的锁(“固有锁”)。

如果您有两个标记为synchronized的不同实例方法,并且不同的线程在同一个对象上并发地调用这些方法,那么这些线程将争用同一个锁。一旦一个线程获得锁,所有其他线程将被关闭,无法使用该对象上的所有同步实例方法。

为了让这两个方法同时运行,它们必须使用不同的锁,就像这样:

class A {
    private final Object lockA = new Object();
    private final Object lockB = new Object();

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

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

同步块语法允许指定一个特定的对象,执行线程需要在该对象上获得内在锁才能进入块。

需要理解的重要一点是,尽管我们在单个方法上添加了“synchronized”关键字,但核心概念是幕后的内在锁。

下面是Java教程描述的关系:

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility. Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

锁定的目的是保护共享数据。只有当每个锁保护不同的数据成员时,才可以使用上面示例代码中所示的单独锁。


Java线程在进入实例同步Java方法时获得一个对象级锁,在进入静态同步Java方法时获得一个类级锁。

在您的示例中,方法(实例)属于同一个类。因此,当一个线程进入java synchronized方法或块时,它会获得一个锁(方法被调用的对象)。因此,在第一个方法完成并释放lock(on object)之前,不能在同一对象上同时调用其他方法。


在你的例子中,你在同一个类实例上同步了两个方法。所以,这两个方法不能同时运行在类A的同一个实例的不同线程上,但是它们可以运行在不同的类A实例上。

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

等于:

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

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


从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

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

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


Two different Threads executing a common synchronized method on the single object, since the object is same, when one thread uses it with synchronized method, it will have to verify the lock, if the lock is enabled, this thread will go to wait state, if lock is disabled then it can access the object, while it will access it will enable the lock and will release the lock only when it's execution is complete. when the another threads arrives, it will verify the lock, since it is enabled it will wait till the first thread completes his execution and releases the lock put on the object, once the lock is released the second thread will gain access to the object and it will enable the lock until it's execution. so the execution will not be not concurrent, both threads will execute one by one, when both the threads use the synchronized method on different objects, they will run concurrently.


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

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

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


是的,它们可以同时运行两个线程。如果创建类的2个对象,每个对象只包含一个锁,并且每个同步方法都需要锁。 如果你想同时运行,创建两个对象然后使用那些对象引用来运行。