2013-08-09 4 views
3

작은 혼란이 있습니다. 아래 코드를 살펴보십시오.정적 동기화 방법 및 비 동기화 정적 메서드 혼동

public class ThreadDemo { 
    //non-static synchronized method 
    synchronized void a(){ 
    actBusy(); 
    } 

    //static synchronized method 
    static synchronized void b(){ 
    actBusy(); 
    } 

    //static method 
    static void actBusy(){ 
    try{ 
     Thread.sleep(1000); 
    } 
    catch(InterruptedException e) { 
     e.printStackTrace(); 
    } 
    } 

    public static void main(String[] args){ 
    final ThreadDemo x = new ThreadDemo(); 
    final ThreadDemo y = new ThreadDemo(); 
    Runnable runnable = new Runnable() { 
     public void run() { 
     int option = (int) (Math.random() * 4); 
     switch (option){ 
      case 0: x.a(); 
      break; 
      case 1: x.b(); 
      break; 
      case 2: y.b(); 
      break; 
      case 3: y.b(); 
      break; 
     } 
     } 
    } ; 
    Thread t1 = new Thread(runnable); 
    Thread t2 = new Thread(runnable); 
    t1.start(); 
    t2.start(); 
    } 
} 

이 시퀀스를 호출 할 수 있음을 알고 있습니다.

x.a() //in Thread-1 
y.b() //in Thread-2 

아직도 내가, 우리가 쉽게 x.a()도 정적 방법이다 actBusy() 방법 호출을 볼 수있는 작은 혼란이 있지만. 메서드 b()은 동기화되지 않은 정적 메서드를 호출하는 정적 동기화 된 메서드입니다. thread-2가 클래스 레벨 잠금을 얻으면 actBusy()의 스레드 -1 호출이 차단되지 않습니까?

스레드가 클래스 수준의 잠금을 얻는 경우 다른 클래스 동기화되지 않은 정적 메서드는 다른 메서드 (인스턴스 메서드)에서 호출 할 수 있도록 열린 상태로 유지됩니다. 왜? 비 정적 synchronized 방법은 인스턴스 객체 (this)에 대한 잠금을 가지고있는 동안

+0

작은 메모이지만'x.a()'와'ThreadDemo.b()'여야합니다. –

답변

2

actBusy() 자체는 동기화되지 않지만 호출자 방법은 같습니다.

스레드 1은 this 개체에 대한 잠금을 획득하고 다른 스레드는 this에 대한 잠금을 보유하지 않으므로 차단하지 않으므로 문제없이 호출 할 수 있습니다.

non-static synchronized 메서드가 this의 현재 인스턴스를 잠그고 class 개체를 잠그지 않았기 때문입니다.

x.a()x 즉 본 예에 대한 잠금을 잡고 다른 스레드가 잠금 본 스레드 해제 현재까지 방법을 xa()를 입력 할 수 없습니다.

스레드 1 ->x.a()//acquires lock and holds it

스레드 2 --->x.a() //blocks here until Thread 1 releases lock on x

편집 :

Class Object != Instance 

그래서 JMM에 따라 서로 다른 개체와 두 개의 스레드 돈이다 ' 서로 간섭한다. 그래서 당신이 그것을 부를 수 있습니다.

편집 2 :

이유는 다른 정적 메서드 호출을 할 수 있습니까? 그것 뒤에 어떤 논리?스레드 1에있어서 일부 공유 상태를 보호하는 데에 statefulMethod() 경우

public static synchronized int statefulMethod(){ 
    //this should be protected 
} 

public static int nonStatefulMethod(){ 
    //Just returns a static value such as 5 
    //so this is thread safe as it does not have any state 
} 

public static synchronized int otherStatefulMethod(){ 
    //this should also be thread safe 
} 

그래서 그래서 클래스 레벨 잠금을 사용

이 있다고 가정하자. 이제 스레드 2는 nonStatefulMethod()을 호출합니다. 그 방법은 스레드로부터 안전하며 거기에는 스레드 블록을 만드는 데 아무런 의미가 없으므로 논리적으로 차단해서는 안됩니다..

스레드 1이 클래스 잠금을 보유하고있는 동안 스레드 3이 otherStatefulMethod()을 호출하면 스레드 3은 해당 메소드가 static-synchornized이기 때문에 기다려야합니다.

+0

그 것을 이해합니다. 정적 메서드가 클래스 수준 메서드라는 논리적 인 설명을 실제로 찾고 있었기 때문에 클래스 수준 개체가 잠기면 다른 정적 메서드를 호출 할 수 있습니까? 그것 뒤에 어떤 논리? – benz

+0

@benz 편집을 참조하십시오. 내가 그것을 밖으로 지우길 바란다 –

+0

나는 그 부분을 완전히 이해한다. 저의 요점은 정적 메소드가 인스턴스 레벨이 아닌 클래스 레벨 메소드라는 것을 알았습니다. b()가 호출되었을 때, thread-2에 의해 클래스 레벨 잠금이 얻어졌다. 내 유일한 혼란은 클래스 잠금이 이미 다른 스레드에 의해 취해 졌을 때 java가 다른 정적 메소드를 호출 할 수있게하는 이유입니다. 나도 알아, 근데 왜? 정적 메서드는 클래스 수준 메서드이기도합니다. – benz

3

static synchronized 방법은 클래스 객체에 대한 잠금을 가지고 - 그래서 두 가지 방법을 동시에 호출 할 수 있으며, 하나 개의 스레드가 동시에 하나를 실행합니다 다른 두 번째를 실행합니다.

그러나 경쟁 조건에는 쓰기가 필요하고 이러한 방법에는 존재하지 않으므로 race condition을 코드에 사용할 수 없습니다.

4

왜 스레드 1에서 actBusy()의 호출이 차단되지 않습니까?

actBusy 메서드가 동기화되지 않았으므로 클래스 수준 잠금을 획득하더라도 비동기 정적 메서드를 호출 할 수 있습니다.

방법을 마킹하는 시점은 synchronized으로 잠금을 설정하는 것입니다. synchronized로 선언 된 메소드 만이 잠금에 종속됩니다. 따라서 잠금을 획득 한 경우 (클래스 레벨 잠금이라고 가정) non-synchronized 메소드는 이전과 동일하게 작동하고 획득 된 잠금을 인식하지 못합니다. 이를 통해 어느 메소드를 차단해야하는지, 어떤 메소드를 차단해야하는지 결정할 수 있습니다.

+0

. 그게 내가 논리적으로 혼란스러워, 정적 메서드는 클래스 수준의 메서드입니다, 그래서 일단 클래스 수준의 개체가 잠겨있다, 왜 다른 정적 메서드에 대한 호출을 허용합니까? 그것 뒤에 어떤 논리? – benz

+1

는 약간의 설명을 덧붙였다 – Tala

1

잠금 개체는 계층 적 구조가 아닙니다. 따라서 클래스 자체에 대한 잠금을 얻는 것은 클래스 인스턴스에 대한 잠금보다 우선하지 않습니다. 이들은 별도의 잠금 오브젝트이며 동일한 오브젝트에 대해 잠금을 시도하는 코드 만 차단합니다.

그래서 스레드가 정적 동기화 된 메서드를 입력하면 차단 될 스레드는 동일한 클래스에서 정적 동기화 된 메서드를 입력하려는 스레드뿐입니다. 비 정적 동기화 된 메소드를 입력하려는 스레드는 영향을받지 않습니다. 동일한 스레드 인스턴스에 비 정적 동기화 된 메소드를 입력하려고하는 스레드와 만 경쟁합니다.

아래의 의견에 대해서는 synchronized으로 표시된 정적 방법 만 클래스 수준 잠금이 적용됩니다. 다른 정적 메서드를 차단하려면 synchronized으로 표시해야합니다.

왜 이런 경우입니까? 글쎄, 컴파일러가 을 모두 잠글 필요가 있다고 가정하는 것은 다소 무리한 일일 것입니다.은 단순히 synchronized으로 표시되어 있기 때문에 정적 메서드 만 사용하면됩니다. 프로그래머는 스레드 안전성을 보장하기 위해 동기화되어야하는 메서드를 알고 있다고 가정합니다.

+0

이것은 나의 혼란의 점이 아니다. 혼란 스러울 점은 일단 클래스 수준의 잠금이 스레드에 의해 잡히면 다른 정적 메서드를 여전히 호출 할 수있는 이유는 무엇입니까? 나는 그것이 허용되지 않는다는 것을 안다. 그러나 나는 생각하고 있었다, 그것은 그것이 왜 그런지에 관해 안다. – benz

+1

@benz 위의 마지막 단락을 참조하십시오. –

+0

그냥 바보 같은 질문입니다. 정적 메서드가 클래스 수준의 개체를 사용하여 호출 할 때 '이'uptil 존재하지 않습니다. – benz

관련 문제