Java 클래스 잠금, 객체 잠금, 개인 잠금 충돌 테스트

클래스 자물쇠와 대상 자물쇠가 충돌합니까?대상 자물쇠와 개인 자물쇠가 충돌합니까?실례를 통해 설명하다.
1. 관련 약정
뒷글의 묘사를 명확히 하기 위해 본고가 언급한 자물쇠에 대한 정의는 다음과 같다.
1. 클래스 자물쇠: 코드에 있는 방법에static과synchronized의 자물쇠를 추가하거나synchronized(xx.class)의 코드 세그먼트, 예를 들어 아래의 increament()를 추가한다.
2. 대상 자물쇠: 코드에 있는 방법에synchronized의 자물쇠를 추가하거나synchronized(this)의 코드 세그먼트, 예를 들어 아래의synOnMethod()와synInMethod()를 추가한다.
3. 개인 자물쇠: 클래스 내부에서private Object lock과 같은 개인 속성을 설명하고 자물쇠를 채워야 하는 코드 세그먼트synchronized(lock), 예를 들어 다음의synMethod With Obj()를 표시합니다.
2. 테스트 코드
1. 시작 클래스 만들기 ObjectLock

public class ObjectLock {
 public static void main(String[] args) {
  System.out.println("start time = " + System.currentTimeMillis()+"ms");
  LockTestClass test = new LockTestClass();
  for (int i = 0; i < 3; i++) {
   Thread thread = new ObjThread(test, i);
   thread.start();
  }
 }
}
2. 동기화 방법을 시작하는 데 사용할 스레드 클래스 ObjThread를 작성합니다. (run 방법이 다른 테스트를 위해 조정될 수 있음을 주의하십시오.)

public class ObjThread extends Thread {
 LockTestClass lock;
 int i = 0;

 public ObjThread(LockTestClass lock, int i) {
  this.lock = lock;
  this.i = i;
 }

 public void run() {
  //
//  lock.noSynMethod(this.getId(),this);
  // 1, synchronized synInMethod
  lock.synInMethod();
  // 2, synchronized(this)
//  lock.synOnMethod();
  // , synchronized(object)
//  lock.synMethodWithObj();
  // , static synchronized increment
  LockTestClass.increment();
 }
}

3. 자물쇠를 추가하는 테스트 클래스 LockTestClass를 작성합니다. 여러 가지 자물쇠 추가 방법을 포함합니다.

public class LockTestClass {
 //
 private static int i = 0;
    //
 private Object object = new Object();

 /**
  * &lt;p&gt;
  *
  *
  * @param threadID
  * @param thread
  */
 public void noSynMethod(long threadID, ObjThread thread) {
  System.out.println("nosyn: class obj is " + thread + ", threadId is"
    + threadID);
 }

 /**
  * 1
  */
 public synchronized void synOnMethod() {
  System.out.println("synOnMethod begins" + ", time = "
    + System.currentTimeMillis() + "ms");
  try {
   Thread.sleep(2000L);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("synOnMethod ends");
 }

 /**
  * 2, synchronized (this)
  */
 public void synInMethod() {
  synchronized (this) {
   System.out.println("synInMethod begins" + ", time = "
     + System.currentTimeMillis() + "ms");
   try {
    Thread.sleep(2000L);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("synInMethod ends");
  }

 }

 /**
  * 3
  */
 public void synMethodWithObj() {
  synchronized (object) {
   System.out.println("synMethodWithObj begins" + ", time = "
     + System.currentTimeMillis() + "ms");
   try {
    Thread.sleep(2000L);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("synMethodWithObj ends");
  }
 }

 /**
  *
  */
 public static synchronized void increament() {
  System.out.println("class synchronized. i = " + i + ", time = "
    + System.currentTimeMillis() + "ms");
  i++;
  try {
   Thread.sleep(2000L);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
   System.out.println("class synchronized ends.");
 }

}

3. 테스트 결과
1. 클래스 잠금 및 객체 잠금 테스트, ObjectThread의 run 메서드는 다음과 같이 수정됩니다.

public void run() {
  //
//  lock.noSynMethod(this.getId(),this);
  // 1, synchronized synInMethod
  lock.synInMethod();
  // 2, synchronized(this)
//  lock.synOnMethod();
  // , synchronized(object)
//  lock.synMethodWithObj();
  // , static synchronized increment
  LockTestClass.increament();
 }
터미널 출력:

start time = 1413101360231ms
synInMethod begins, time = 1413101360233ms
synInMethod ends
class synchronized. i = 0, time = 1413101362233ms
synInMethod begins, time = 1413101362233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 1, time = 1413101364233ms
synInMethod begins, time = 1413101364233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 2, time = 1413101366234ms
class synchronized ends.
대상 자물쇠 방법(syn In Mothod)이 첫 번째 시작할 때 클래스 자물쇠 방법(increament)보다 2초 빠른 것을 볼 수 있습니다. 이것은syn In Mehtod가 실행할 때 sleep가 2초 동안 실행된 increament이기 때문입니다. 이 두 방법은 하나의 라인을 사용하기 때문에 2초 느립니다. 만약에 increament가run에서syn In Method 앞에 놓으면 첫 번째 시작할 때 increament가 2초 빠릅니다.
한편, 클래스 자물쇠 방법이 시작될 때 다른 라인의 대상 자물쇠 방법도 거의 동시에 시작된다는 것은 양자가 같은 자물쇠를 사용하지 않고 경쟁이 일어나지 않는다는 것을 의미한다.
결론: 유형 자물쇠와 대상 자물쇠는 경쟁이 일어나지 않고 양자의 자물쇠 추가 방법은 서로 영향을 주지 않는다.
2. 개인 자물쇠와 대상 자물쇠, ObjectThread의run 방법은 다음과 같이 수정됩니다.

public void run() {
  //
//  lock.noSynMethod(this.getId(),this);
  // 1, synchronized synInMethod
  lock.synInMethod();
  // 2, synchronized(this)
//  lock.synOnMethod();
  // , synchronized(object)
  lock.synMethodWithObj();
  // , static synchronized increment
//  LockTestClass.increament();
 }
터미널 출력:

start time = 1413121912406ms
synInMethod begins, time = 1413121912407ms.
synInMethod ends.
synMethodWithObj begins, time = 1413121914407ms
synInMethod begins, time = 1413121914407ms.
synInMethod ends.
synMethodWithObj ends
synInMethod begins, time = 1413121916407ms.
synMethodWithObj begins, time = 1413121916407ms
synInMethod ends.
synMethodWithObj ends
synMethodWithObj begins, time = 1413121918407ms
synMethodWithObj ends
클래스 자물쇠와 대상 자물쇠와 매우 유사합니다.
결론: 사유 자물쇠와 대상 자물쇠도 경쟁이 일어나지 않고 양자의 자물쇠 추가 방법은 서로 영향을 주지 않는다.
3. synchronized는 방법과 synchronized(this)에 직접 추가되며, ObjectThread의 run 방법은 다음과 같이 수정됩니다.

public void run() {
  //
//  lock.noSynMethod(this.getId(),this);
  // 1, synchronized synInMethod
  lock.synInMethod();
  // 2, synchronized(this)
  lock.synOnMethod();
  // , synchronized(object)
//  lock.synMethodWithObj();
  // , static synchronized increment
//  LockTestClass.increament();
 }
터미널 출력:

start time = 1413102913278ms
synInMethod begins, time = 1413102913279ms
synInMethod ends
synInMethod begins, time = 1413102915279ms
synInMethod ends
synOnMethod begins, time = 1413102917279ms
synOnMethod ends
synInMethod begins, time = 1413102919279ms
synInMethod ends
synOnMethod begins, time = 1413102921279ms
synOnMethod ends
synOnMethod begins, time = 1413102923279ms
synOnMethod ends
이를 통해 알 수 있듯이 양자는 엄격하게 직렬 출력을 한다. (물론 다시 실행할 때synInMethod를 먼저 실행하느냐, 아니면synOnMethod를 먼저 실행하느냐가 확정된 것이 아니라 누가 자물쇠를 얻었느냐에 달려 있다.)
결론:synchronized를 직접 방법에 추가하고synchronized(this)는 모두 현재 대상에 대한 자물쇠를 추가하는 것이다. 양자의 자물쇠 추가 방법은 경쟁 관계가 될 수 있고 같은 시간에 한 가지 방법만 실행할 수 있다.

좋은 웹페이지 즐겨찾기