synchronized 원 리 는 얼마나 알 고 있 습 니까?

synchronized 자바 프로 그래 밍 의 중요 한 키워드 이자 다 중 스 레 드 프로 그래 밍 에서 없어 서 는 안 되 거나 없어 서 는 안 되 는 사람 입 니 다.본 고 는 그것 의 사용 과 자물쇠 의 중요 한 개념 에 대해 분석 하고 자 한다.
사용 및 원리
synchronized 는 중량급 자물쇠 로 동기 화 작업 을 실현 합 니 다. 자바 대상 자물쇠 에는 세 가지 사용 방식 이 있 습 니 다.
  • 일반 방법 에서 사용 되 며 잠 금 은 현재 인 스 턴 스 대상 입 니 다.
  • 정적 방법 에서 사용 하여 현재 클래스 의 대상 을 잠 급 니 다.
  • 코드 블록 에서 사용 되 며 자 물 쇠 는 코드 블록 에 설 정 된 대상 입 니 다.

  • 쓰다
    코드 에서 사용 하 는 방법 은 다음 과 같다.
    일반 방법 사용:
    /**
     *  :yt
     *  :t
     */
    public class SynchronizedMethodDemo{
        public synchronized void demo(){
            // ......
        }
    }
    

    정적 방법 사용:
    /**
     *  :yt
     *  :t
     */
    public class SynchronizedMethodDemo{
        public synchronized static void staticDemo(){
            // ......
        }
    }
    

    코드 블록 에서 사용:
    /**
     *  :yt
     *  :y
     */
    public class SynchronizedDemo{
        public void demo(){
            synchronized (SynchronizedDemo.class){
                // ......
            }
        }
    }
    

    실현 원리
    방법 과 코드 블록 의 실현 원 리 는 서로 다른 방식 을 사용한다.
    부호 블록
    대상 마다 하나의 monitor 대상 이 있 고 코드 블록 {}monitorentermonitorexit 명령 이 삽입 된다.monitorenter 명령 을 실행 할 때 monitor 대상 에 들 어가 자 물 쇠 를 가 져 오고 monitorexit 명령 을 실행 할 때 monitor 대상 에서 자 물 쇠 를 방출 합 니 다.같은 시각 에 하나의 스 레 드 만 monitorenter 에 들 어 갈 수 있다.
    먼저 SynchronizedDemo.java 사용 javac SynchronizedDemo.java 명령 을 SynchronizedDemo.class 로 컴 파일 합 니 다.그리고 javap -c SynchronizedDemo.class 바이트 코드 를 역 컴 파일 합 니 다.
    Compiled from "SynchronizedDemo.java"
    public class SynchronizedDemo {
      public SynchronizedDemo();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."":()V
           4: return
    
      public void demo();
        Code:
           0: ldc           #2                  // class SynchronizedDemo
           2: dup
           3: astore_1
           4: monitorenter  //    monitor
           5: aload_1
           6: monitorexit  //    monitor
           7: goto          15
          10: astore_2
          11: aload_1
          12: monitorexit  //    monitor
          13: aload_2
          14: athrow
          15: return
        Exception table:
           from    to  target type
               5     7    10   any
              10    13    10   any
    }
    

    위 에서 인 코딩 된 코드 는 두 개의 monitorexit 명령 이 있 고 하 나 는 이상 한 위치 에 삽입 되 며 하 나 는 방법 끝 위치 에 삽입 된다.
    방법.
    방법 중의 synchronized 은 코드 블록 에서 실현 되 는 방식 과 달리 방법 에 ACC_SYNCHRONIZED 라 는 표 지 를 추가 합 니 다. 호출 방법 이 있 을 때 먼저 ACC_SYNCHRONIZED 표지 가 있 는 지 확인 하고 존재 하면 monitor 대상, 호출 monitorentermonitorexit 명령 을 받 습 니 다.javap -v -c SynchronizedMethodDemo.class 명령 을 통 해 클래스 를 역 컴 파일 SynchronizedMethodDemo 합 니 다.-v 매개 변 수 는 -verbose 출력 반 컴 파일 의 추가 정 보 를 나타 낸다.다음은 일반적인 방법 을 역 컴 파일 하 는 것 을 예 로 들 자.
    Classfile /E:/SynchronizedMethodDemo.class
      Last modified 2020-6-28; size 381 bytes
      MD5 checksum 55ca2bbd9b6939bbd515c3ad9e59d10c
      Compiled from "SynchronizedMethodDemo.java"
    public class SynchronizedMethodDemo
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #5.#13         // java/lang/Object."":()V
       #2 = Fieldref           #14.#15        // java/lang/System.out:Ljava/io/PrintStream;
       #3 = Methodref          #16.#17        // java/io/PrintStream.println:()V
       #4 = Class              #18            // SynchronizedMethodDemo
       #5 = Class              #19            // java/lang/Object
       #6 = Utf8               
       #7 = Utf8               ()V
       #8 = Utf8               Code
       #9 = Utf8               LineNumberTable
      #10 = Utf8               demo
      #11 = Utf8               SourceFile
      #12 = Utf8               SynchronizedMethodDemo.java
      #13 = NameAndType        #6:#7          // "":()V
      #14 = Class              #20            // java/lang/System
      #15 = NameAndType        #21:#22        // out:Ljava/io/PrintStream;
      #16 = Class              #23            // java/io/PrintStream
      #17 = NameAndType        #24:#7         // println:()V
      #18 = Utf8               SynchronizedMethodDemo
      #19 = Utf8               java/lang/Object
      #20 = Utf8               java/lang/System
      #21 = Utf8               out
      #22 = Utf8               Ljava/io/PrintStream;
      #23 = Utf8               java/io/PrintStream
      #24 = Utf8               println
    {
      public SynchronizedMethodDemo();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."":()V
             4: return
          LineNumberTable:
            line 5: 0
    
      public synchronized void demo();
        descriptor: ()V
        flags: ACC_PUBLIC, ACC_SYNCHRONIZED     // ACC_SYNCHRONIZED   
        Code:
          stack=1, locals=1, args_size=1
             0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
             3: invokevirtual #3                  // Method java/io/PrintStream.println:()V
             6: return
          LineNumberTable:
            line 8: 0
            line 10: 6
    }
    SourceFile: "SynchronizedMethodDemo.java"
    

    위 에서 코드 블록 과 방법의 실현 방식 에 대해 탐구 했다.
  • 코드 블록 은 컴 파일 된 코드 에 monitorentermonitorexit 명령 을 추가 합 니 다.
  • 방법 에 표 지 를 추가 ACC_SYNCHRONIZED 함으로써 호출 여 부 를 결정 한다 monitor.

  • Java 개체 헤더synchronized 잠 긴 관련 데 이 터 는 자바 대상 머리 에 저 장 됩 니 다.자바 개체 헤드 가 가리 키 는 핫 스 팟 가상 머 신의 대상 헤드 는 2 글자 너비 또는 3 글자 너비 저장 대상 헤드 를 사용한다.
  • 첫 번 째 부분 은 실 행 될 때의 데 이 터 를 저장 하고 hashCode, 잠 금 표시 위치, 잠 금 편향 여부, GC 세대 연령 등 정 보 를 Mark Word 라 고 한다.
  • 두 번 째 부분 에 대상 유형 데 이 터 를 저장 하 는 지침.
  • 세 번 째 부분 은 대상 이 배열 이 라면 이 부분 으로 배열 의 길 이 를 저장 합 니 다.

  • Java 개체 헤더 Mark Word 저장 내용:
    저장 내용
    표지 비트
    상태.
    대상 의 hashCode, GC 세대 구분 연령
    01
    자물쇠 없 음
    스 택 의 잠 금 기록 을 가리 키 는 지침
    00
    경량급 자물쇠
    헤비급 자 물 쇠 를 가리 키 는 지침
    10
    헤비급 자물쇠
    비다
    11
    GC 태그
    스 레 드 ID, Epoch (타임 스탬프), GC 세대 구분 연령
    01
    편향 자물쇠
    자물쇠 업그레이드
    synchronized 는 헤비급 잠 금 이 라 고 하지만 자바 SE 1.6 은 이 잠 금 의 성능 을 최적화 하기 위해 잠 금 의 성능 소 모 를 줄 이 고 도입 한다.
    자물쇠 의 높 고 낮 음 단 계 는 이다.
    그 중에서 자물쇠 의 업 그 레이 드 는 거 스 를 수 없고 낮은 것 에서 고급 으로 만 올 라 갈 수 있 으 며 높 은 것 에서 낮은 것 으로 내 려 갈 수 없다.
    편향 자물쇠
    편향 잠 금 은 다 중 스 레 드 경쟁 없 이 프로그램의 운행 성능 을 향상 시 키 기 위해 사용 되 는 잠 금 이다.Mark Word 에 하나의 값 을 저장 하여 편향 잠 금 여 부 를 표시 합 니 다. 32 비트 가상 컴퓨터 와 64 비트 가상 컴퓨터 에서 모두 하나의 바이트 로 저장 되 고 0 은 비 편향 잠 금 이 며 1 은 편향 잠 금 입 니 다.
    첫 번 째 스 레 드 에서 편향 잠 금 을 가 져 올 때 Mark Word 의 편향 잠 금 표 지 를 1 로 설정 하고 CAS 동작 으로 이 스 레 드 의 ID 를 기록 합 니 다.편향 잠 금 스 레 드 를 가 져 와 잠 금 가 져 오기 에 다시 들 어 갈 때 Mark Word 현재 스 레 드 ID 가 저장 되 어 있 는 지 판단 하기 만 하면 됩 니 다. 그렇다면 잠 금 가 져 오기 동작 을 다시 하지 않 고 이 자 물 쇠 를 직접 가지 고 있 습 니 다.
    잠 금 해제
    다른 스 레 드 가 나타 나 면 편향 자 물 쇠 를 가 져 와 경쟁 상태 에 있 게 하려 고 시도 하면 현재 편향 자 물 쇠 는 취 소 됩 니 다.편향 잠 금 을 해제 할 때 우선 편향 잠 금 이 있 는 스 레 드 를 일시 정지 하고 스 레 드 ID 를 비 워 둔 다음 이 스 레 드 가 살아 있 는 지 확인 합 니 다.
  • 스 레 드 가 생존 하지 않 으 면 대상 머리 를 잠 금 상태 로 설정 합 니 다.
  • 스 레 드 가 살아 남 을 때 잠 금 스 택 을 실행 하고 마지막 대상 헤드 는 잠 금 스 레 드 ID 를 가 져 오 거나 잠 금 상태 로 전환 합 니 다.

  • 코드 가 다 중 스 레 드 접근 에서 반드시 실 행 될 것 이 라 고 확 정 했 을 때 이 때 편향 잠 금 은 장점 을 발휘 하지 못 합 니 다. 편향 잠 금 을 계속 사용 하면 너무 번 거 롭 고 시스템 에 불필요 한 성능 비용 을 가 져 다 줄 수 있 습 니 다. 이때 JVM 파라미터 -XX:BiasedLocking=false 를 설정 하여 편향 잠 금 을 닫 을 수 있 습 니 다.
    경량급 자물쇠
    코드 가 동기 블록 에 들 어 갈 때 대상 헤드 가 잠 겨 있 지 않 으 면 JVM 은 현재 스 레 드 의 스 택 정 에 공간 을 만 들 고 잠 겨 있 는 대상 헤드 Mark Word 에 복사 합 니 다. 이 복사 한 Mark WordDisplaced Mark Word 이 라 고 합 니 다.그리고 CAS 동작 을 사용 하여 잠 금 대상 헤드 의 Mark Word 를 가리 키 는 지침 으로 업데이트 합 니 다.업데이트 에 성공 하면 현재 스 레 드 는 자 물 쇠 를 얻 습 니 다. 실패 하면 JVM 은 먼저 잠 금 대상 Mark Word 이 현재 스 레 드 를 가리 키 는 지, 현재 스 레 드 를 가리 키 는 지 확인 합 니 다. 그러면 현재 스 레 드 는 자 물 쇠 를 가지 고 있 습 니 다. 그렇지 않 으 면 다 중 스 레 드 경쟁 이 존재 합 니 다그래서 이 과정 은 CPU 를 소모 하 는 과정 이다.경량급 자물쇠 가 경쟁 상태 에 존재 하고 경량급 자 물 쇠 를 자전 적 으로 가 져 오 는 데 실 패 했 을 때 경량급 자 물 쇠 는 중량급 자물쇠 로 팽창 하고 자물쇠 대상 Mark Word 은 중량급 자 물 쇠 를 가리 키 는 지침 으로 업데이트 되 며 자 물 쇠 를 가 져 오 는 스 레 드 가 차단 상태 에 들 어가 기 를 기다린다.
    자 물 쇠 를 풀다
    경량급 잠 금 해 제 는 CAS 작업 으로 Mark Word 로 교체 하 는 것 으로, 교체 에 성공 하면 동기 화 작업 이 완료 됐다 는 뜻 이다.실패 하면 다른 경쟁 스 레 드 가 이 경량급 자 물 쇠 를 가 져 오 려 고 시 도 했 음 을 나타 낸다. 자 물 쇠 를 풀 면서 다른 막 힌 스 레 드 를 깨 우 고 깨 워 진 스 레 드 는 다시 경쟁 자 물 쇠 를 가 져 가 야 한다.
    총결산
    분석 synchronized 의 사용 과 자바 SE 1.6 업그레이드 최적화 잠 금 후의 디자인 을 통 해 알 수 있 듯 이 주로 해결 하 는 것 은 2 급 상대 적 으로 가 벼 운 편향 잠 금 과 경량급 잠 금 을 더 넣 어 중량급 잠 금 의 성능 소 모 를 최적화 하 는 것 이지 만 이것 이 반드시 최적화 역할 을 하 는 것 은 아니다.주로 대부분 상황 에서 다 중 스 레 드 경쟁 과 같은 스 레 드 가 여러 번 자 물 쇠 를 얻 는 최적화 가 존재 하지 않 는 다 는 것 을 해결 하 는 것 도 평소에 인 코딩 에서 많이 관찰 하고 반성 한 평가 방안 이다.

    좋은 웹페이지 즐겨찾기