Programing

같은 클래스에서 두 개의 메소드를 동기화하면 동시에 실행할 수 있습니까?

lottogame 2020. 6. 25. 08:05
반응형

같은 클래스에서 두 개의 메소드를 동기화하면 동시에 실행할 수 있습니까?


같은 클래스에서 두 개의 메소드를 동기화 하면 동일한 객체 에서 동시에 실행할 수 있습니까? 예를 들면 다음과 같습니다.

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

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

methodA()두 개의 다른 스레드에서 동일한 객체에서 두 번 실행할 수 없다는 것을 알고 있습니다 . 에서 같은 것 methodB().

그러나 여전히 실행중인 methodB()동안 다른 스레드에서 실행할 수 methodA()있습니까? (같은 객체)


두 방법 모두 같은 모니터를 잠급니다. 따라서 다른 스레드의 동일한 객체에서 동시에 실행할 수 없습니다 (두 방법 중 하나는 다른 방법이 완료 될 때까지 차단됨).


예제에서 methodA와 methodB는 인스턴스 메소드입니다 (정적 메소드와 반대). 퍼팅 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
        }
    }
}

여기서 동기화 된 블록 구문은 실행 스레드가 블록에 들어가기 위해 본질적 잠금을 획득해야하는 특정 객체를 지정할 수있게합니다.

이해해야 할 중요한 점은 개별 메소드에 "동기화 된"키워드를 사용하더라도 핵심 개념은 장면 뒤에 숨겨진 고유 개념이라는 것입니다.

다음은 Java 학습서 가 관계를 설명하는 방법입니다 .

동기화는 내장 잠금 또는 모니터 잠금이라고하는 내부 엔터티를 기반으로합니다. (API 사양은 종종이 엔티티를 단순히 "모니터"라고합니다.) 내장 잠금은 동기화의 두 측면에서 중요한 역할을합니다. 즉 객체 상태에 대한 독점 액세스를 강화하고 가시성에 필수적인 관계를 설정합니다.

모든 객체에는 관련된 고유 잠금이 있습니다. 일반적으로 객체 필드에 독점적이고 일관된 액세스가 필요한 스레드는 객체에 액세스하기 전에 객체의 본질적 잠금을 획득 한 다음 완료되면 본질적 잠금을 해제해야합니다. 스레드는 잠금을 획득하고 잠금을 해제 한 시간 사이에 고유 잠금을 소유한다고합니다. 스레드가 내장 잠금을 소유하는 한 다른 스레드는 동일한 잠금을 얻을 수 없습니다. 다른 스레드는 잠금을 획득하려고 시도 할 때 차단됩니다.

잠금의 목적은 공유 데이터를 보호하는 것입니다. 각 잠금이 다른 데이터 멤버를 보호하는 경우에만 위의 예제 코드에 표시된대로 별도의 잠금을 사용합니다.


Java Thread는 인스턴스 동기화 Java 메소드에 들어갈 때 오브젝트 레벨 잠금을 획득하고 정적 동기화 Java 메소드에 들어갈 때 클래스 레벨 잠금을 획득합니다 .

귀하의 경우, 메소드 (인스턴스)는 동일한 클래스입니다. 따라서 스레드가 Java 동기화 된 메소드 또는 블록에 들어갈 때마다 잠금 (메소드가 호출되는 객체)을 얻습니다. 따라서 첫 번째 메소드가 완료되고 오브젝트에서 잠금이 해제 될 때까지 동일한 오브젝트에서 동시에 다른 메소드를 호출 할 수 없습니다.


귀하의 경우 동일한 클래스 인스턴스에서 두 개의 메소드를 동기화했습니다. 따라서이 두 가지 방법은 동일한 클래스 A 인스턴스의 다른 스레드에서 동시에 실행될 수 없습니다. 그러나 다른 클래스 A 인스턴스에서는 가능합니다.

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

와 같다:

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

오라클 문서 링크에서

메소드를 동기화하면 두 가지 효과가 있습니다.

첫째, 동일한 객체에서 동기화 된 메소드를 두 번 호출하여 인터리브 할 수 없습니다. 하나의 스레드가 객체에 대해 동기화 된 메소드를 실행하는 경우 첫 번째 스레드가 객체와 함께 완료 될 때까지 동일한 객체 블록에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드 (일시 중단).

둘째, 동기화 된 메소드가 종료되면 동일한 오브젝트에 대한 동기화 된 메소드의 후속 호출과의 사전 관계를 자동으로 설정합니다. 이를 통해 객체 상태의 변경 사항이 모든 스레드에 표시됩니다.

이것은 귀하의 질문에 대답 할 것입니다 : 동일한 객체에서 첫 번째 동기화 된 메소드 실행이 진행 중일 때 두 번째 동기화 된 메소드를 호출 할 수 없습니다.

내장 잠금 및 잠금 동작을 이해하려면 이 설명서 페이지살펴보십시오 .


코드를 아래 코드로 생각하십시오.

class A {

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

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

따라서 메소드 레벨에서 동기화는 단순히 동기화 됨 (this)을 의미합니다. 스레드가이 클래스의 메소드를 실행하는 경우 실행을 시작하기 전에 잠금을 확보하고 메소드 실행이 완료 될 때까지 보유합니다.

그러나 methodA ()가 계속 실행되는 동안 다른 스레드에서 methodB ()를 실행할 수 있습니까? (같은 객체)

실제로는 불가능합니다!

따라서 여러 스레드가 동일한 객체에서 동시에 여러 개의 동기화 된 메소드를 실행할 수 없습니다.


모든 명확성을 위해서, 정적 동기화 및 비 정적 동기화 방법은 객체 레벨 잠금 및 다른 클래스 레벨 잠금을 가지고 있기 때문에 동시에 또는 동시에 실행될 수 있습니다.


You are synchronizing it on object not on class. So they cant run simultaneously on the same object


No it is not possible, if it were possible then both method could be updating same variable simultaneously which could easily corrupt the data.


The key idea with synchronizing which does not sink in easily is that it will have effect only if methods are called on the same object instance - it has already been highlighted in the answers and comments -

Below sample program is to clearly pinpoint the same -

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();
    }
}
}

Notice the difference in output of how simultaneous access is allowed as expected if methods are called on different object instances.

Ouput with noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects() commented -the output is in order methodA in > methodA Out .. methodB in > methodB Out Ouput with *noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects()* commented

and Ouput with synchronizedEffectiveAsMethodsCalledOnSameObject() commented - the output shows simultaneous access of methodA by Thread1 and Thread0 in highlighted section -

Ouput with *synchronizedEffectiveAsMethodsCalledOnSameObject()* commented

Increasing the number of threads will make it even more noticeable.


Yes, they can run simultaneously both threads. If you create 2 objects of the class as each object contains only one lock and every synchronized method requires lock. So if you want to run simultaneously, create two objects and then try to run by using of those object reference.


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 varify 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 varify 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 untill 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.

참고URL : https://stackoverflow.com/questions/15438727/if-i-synchronized-two-methods-on-the-same-class-can-they-run-simultaneously

반응형