>  기사  >  Java  >  Java 동기화란 무엇입니까?

Java 동기화란 무엇입니까?

WBOY
WBOY앞으로
2023-05-14 08:28:051660검색

Synchronized란 무엇인가

Java 독자 여러분, syncinized 키워드가 낯설지 않으실 겁니다. 이는 다양한 미들웨어 소스 코드나 JDK 소스 코드에서 볼 수 있습니다. 멀티스레딩에 사용하려면 동기화가 스레드 안전성을 보장할 수 있다는 것을 알고 있어야 합니다.

  • 호출됨: mutex 잠금(동시에 하나의 스레드만 실행될 수 있으며, 다른 스레드는 대기함)

  • 호출됨: 비관적 잠금(동시에 하나의 스레드만 실행될 수 있음, 다른 스레드는 대기함) 기다릴게요)

  • JVM 가상 머신이 이를 구현하는 데 도움이 될 것입니다. 개발자는 동기화된 키워드만 사용하면 됩니다.

  • 사용할 때 코드 조각(중요 섹션)의 원자성과 가시성을 보장하기 위해 객체를 잠금 뮤텍스로 사용해야 합니다

  • .

바이트코드 수준에서 동기화 키워드를 구문 분석

케이스로 시작하는 것이 가장 적합합니다.

class Demo1{
    // 互斥对象
    static Object object = new Object();
    // 竞争条件
    static int cout = 0;
    public static void main(String[] args) {
        // 互斥
        synchronized(object){
            // 以下是临界区
            cout++;
            System.out.println("synchronized");
        }
    }
}

자바 코드만으로는 아무것도 알 수 없고, 자바 프로그램은 바이트코드 파일로 컴파일되므로 바이트코드를 파싱합니다

상수 풀:
   #1 = Methodref          #7.#26         // java/lang/Object."7e51f00a783d7eb8f68358439dee7daf":()V
   #2 = Fieldref           #8.#27         // Demo1.object:Ljava /lang/Object;
   #3 = Fieldref           #8.#28         // Demo1.cout:I
   #4 = Fieldref           #29.#30        // java/lang/System.out:Ljava/io/PrintStream;
   # 5 = 문자열             #31            // 동기화됨
   #6 = Methodref          #32.#33        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #7 = 클래스              #34           // java/lang/ 개체
   #8 = 클래스              #35            // Demo1
   #9 = Utf8               개체
  #10 = Utf8               Ljava/lang/Object;
  #11 =              cout
  #12 = Utf8               I
  #13 = Utf8               7e51f00a783d7eb8f68358439dee7daf
#14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               main
  #18 = f8               ([Ljava/lang/String;)V
  #19 = Utf8               StackMapTable
  #20 = 클래스              #36            // "[Ljava/lang/String;"
  #21 = 클래스              #34            // java/lang/Object
  #22 = 클래스              #37           // java/lang/Throwable
  #23 = Utf8                 #24 = Utf8               SourceFile
  #25 = Utf8               Demo1.java
  #26 = NameAndType        #13:#14        // "7e51f00a783d7eb8f68358439dee7daf":()V
  #27 = NameAndType        #9:#10         // 객체 :Ljava/lang/Object;
  #28 = NameAndType        #11:#12        // cout:I
  #29 = 클래스              #38            // java/lang/System
  #30 = NameAndType        #39:#40       // 출력: Ljava/io/PrintStream;
  #31 = Utf8               동기화됨
  #32 = 클래스              #41            // java/io/PrintStream
  #33 = 이름 및 유형        #42:#43        // 인쇄 ln:(Ljava/lang/String;)V
#34 = Utf8               java/lang/Object
  #35 = Utf8               Demo1
  #36 = Utf8               [Ljava/lang/String;
  #37 = Utf8               java/lang /Throwable
  #38 = Utf8               java/lang/System
  #39 = Utf8               out
  #40 = Utf8               Ljava/io/PrintStream;
  #41 = Utf8               java/io/PrintStream
  #42 = Utf8               println
#43 = Utf8               (Ljava/lang/String;)V
         0: getstatic     #2 // 从2号常weight池中拿到静态变weight,压入到操事数栈中                  
         3: dup                     // 把操作数栈栈顶的对象赋值一份
4: ASTORE_1 // 로컬 변수 테이블 1번에 연산 번호 스택의 데이터를 저장하고 잠금 해제 사용
5: Monitorenter // 상호 잠금 열기, 이것도 동기화된 바이트 코드 레벨입니다
6: getstation #3 // / 상수 풀 2번에서 정적 변수를 가져와서 피연산자 스택에 푸시합니다.
9: icont_1 9: icont_1 // 상수 1을 피연산자 스택에 푸시합니다.
10: iadd 10: iadd 두 가지의 데이터를 소비합니다. 피연산자 스택을 추가한 후 스택 맨 위로 푸시
            11: putstatic     #3       // 피연산자 스택 맨 위에 있는 변수를 상수 풀 3번에 할당
    14: getstatic     #4                                                        17: LDC #5 // 5번 일반 풀의 기호를 분석하고 문자열 상수 "Synchronized"를 가져옵니다.
19: Invirtual #6 // Println 함수를 실행하고 2개의 작업 스택을 사용합니다.
22: ALOAD_1 // 1은 1이 됩니다. 로컬에 있는 데이터 변수 테이블 번호가 피연산자 스택에 푸시됩니다.
23: monitorexit // 뮤텍스 잠금의 끝도 동기화된 바이트코드 수준에서 구현됩니다.
24: goto 32 // 32행으로 점프합니다. Re 27: ASTORE_2 // 이상이 있을 수 있으나 잠금이 필요하므로 이상 객체를 로컬 변수 테이블 2에 넣습니다
28: ALOAD_1 // 로컬 변수 테이블 데이터를 연산 번호 스택의 맨 위에 밀어 넣습니다. 스택의 공급용 운영 스택의 스택에 대한 공급용 운영 스택의 스택에 대한 공급용 monitorexit 명령이 사용됩니다
29: monitorexit               // 예외가 있을 수 있지만 잠금 해제해야 합니다. 그렇지 않으면 교착 상태가 됩니다.
30: aload_2 32: Return                                    // 함수는


을 반환합니다. 위의 내용은 바이트코드입니다. 마지막으로, 동기화된 키워드는 바이트로 분석되어 monitorenter 및 monitorexit 바이트코드 명령어로 사용됩니다. 두 개의 바이트코드 명령어가 있으면 뮤텍스 개체가 피연산자 스택에 푸시되어 monitorenter 및 monitorexit 명령어가 사용됩니다.

그래서 다음 글은 핫스팟 소스 코드로 가서 monitorenter 및 monitorexit 바이트코드 명령어의 세부 프로세스를 파싱하는 것입니다.

Synchronized Lock과 ReentrantLock의 차이점

이것은 매우 일반적인 인터뷰 질문이며 인터뷰에서 매우 자주 묻는 질문입니다.

유사점:

둘 다 뮤텍스 잠금을 구현합니다.

차이점:

Synchronized 기반 JVM의 내부 구현인 ReentrantLock은 Java 수준에서 구현됩니다(그러나 ReentrantLock의 핵심 코드는 여전히 C++ 코드를 호출합니다).

  • Synchronized는 1.6 이후에 최적화되었습니다. 잠금의 강도는 스레드 경쟁의 강도에 따라 증가하며(일반적으로 잠금 업그레이드라고 함) ReentrantLock이 더 적합합니다. 잠금 강도 선택이 약간 엄격합니다.

  • ReentrantLock은 잠금 강도 선택이 약간 엄격하지만 공정함과 불공정 중에서 선택할 수 있지만 동기화는 불공평한 잠금만 선택할 수 있습니다.

  • ReentrantLock의 조건부 대기 대기열은 고도로 맞춤화된 다중 잠금을 생성할 수 있습니다. 동기화 하단에는 대기열이 하나만 있습니다.

  • ReentrantLock에서는 사용자가 수동으로 자물쇠를 열고 수동으로 잠금을 해제해야 합니다. 동기화 키워드의 하위 레이어는 바이트코드를 통해 자동으로 구현됩니다

위 내용은 Java 동기화란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제