JVM (Java Virtual Machine)이 스레드 동기화를 수행하는 방법

모든 Java 프로그램은 Java 가상 머신의 기계어 인 바이트 코드를 포함하는 클래스 파일로 컴파일됩니다. 이 기사에서는 관련 바이트 코드를 포함하여 Java 가상 머신에서 스레드 동기화를 처리하는 방법을 살펴 봅니다. (1,750 단어)

이번 달 Under The Hood 에서는 Java 언어와 JVM (Java Virtual Machine) 모두에서 스레드 동기화를 살펴 봅니다. 이 기사는 내가 지난 여름에 시작한 일련의 긴 바이트 코드 기사 중 마지막 기사입니다. 스레드 동기화와 직접 관련된 단 두 개의 opcode, 즉 모니터에 들어가고 나가는 데 사용되는 opcode를 설명합니다.

스레드 및 공유 데이터

Java 프로그래밍 언어의 강점 중 하나는 언어 수준에서 멀티 스레딩을 지원한다는 것입니다. 이러한 지원의 대부분은 여러 스레드간에 공유되는 데이터에 대한 액세스 조정에 중점을 둡니다.

JVM은 실행중인 Java 애플리케이션의 데이터를 여러 런타임 데이터 영역 (하나 이상의 Java 스택, 힙 및 메소드 영역)으로 구성합니다. 이러한 메모리 영역에 대한 배경 지식은 첫 번째 Under the Hood 기사 "간단하고 의미있는 가상 머신"을 참조하십시오.

Java 가상 머신 내에서 각 스레드는 스레드가 호출 한 각 메소드의 로컬 변수, 매개 변수 및 리턴 값을 포함하여 다른 스레드가 액세스 할 수없는 데이터를 포함 하는 Java 스택을 부여 받습니다. 스택의 데이터는 기본 유형 및 객체 참조로 제한됩니다. JVM에서는 실제 개체의 이미지를 스택에 배치 할 수 없습니다. 모든 개체는 힙에 있습니다.

JVM 내부에는 이 하나 뿐이며 모든 스레드가이를 공유합니다. 힙에는 개체 만 포함됩니다. 힙에 고독한 기본 유형이나 객체 참조를 배치 할 방법이 없습니다. 이러한 것들은 객체의 일부 여야합니다. 배열은 기본 유형의 배열을 포함하여 힙에 상주하지만 Java에서는 배열도 객체입니다.

Java 스택 및 힙 외에도 JVM에 상주 할 수있는 다른 장소 데이터는 프로그램에서 사용하는 모든 클래스 (또는 정적) 변수를 포함 하는 메소드 영역 입니다. 메소드 영역은 기본 유형 및 객체 참조 만 포함한다는 점에서 스택과 유사합니다. 그러나 스택과 달리 메서드 영역의 클래스 변수는 모든 스레드에서 공유됩니다.

개체 및 클래스 잠금

위에서 설명한 것처럼 Java 가상 머신의 두 메모리 영역에는 모든 스레드가 공유하는 데이터가 포함됩니다. 이것들은:

  • 모든 개체를 포함하는 힙
  • 모든 클래스 변수를 포함하는 메서드 영역

여러 스레드가 동일한 개체 또는 클래스 변수를 동시에 사용해야하는 경우 데이터에 대한 액세스를 적절하게 관리해야합니다. 그렇지 않으면 프로그램이 예측할 수없는 동작을합니다.

여러 스레드 간의 공유 데이터 액세스를 조정하기 위해 JVM (Java Virtual Machine)은 잠금 을 각 객체 및 클래스와 연관시킵니다 . 잠금은 한 번에 하나의 스레드 만 "소유"할 수있는 권한과 같습니다. 스레드가 특정 객체 나 클래스를 잠그고 자하면 JVM에 요청합니다. 스레드가 JVM에 잠금을 요청한 후 어느 시점에 JVM이 잠금을 스레드에 제공합니다. 스레드가 더 이상 잠금을 필요로하지 않으면 JVM으로 리턴합니다. 다른 스레드가 동일한 잠금을 요청한 경우 JVM은 해당 스레드에 잠금을 전달합니다.

클래스 잠금은 실제로 객체 잠금으로 구현됩니다. JVM은 클래스 파일을로드 할 때 class의 인스턴스를 만듭니다 java.lang.Class. 클래스를 잠그면 실제로 해당 클래스의 Class객체를 잠그는 것입니다 .

스레드는 인스턴스 또는 클래스 변수에 액세스하기 위해 잠금을 얻을 필요가 없습니다. 그러나 스레드가 잠금을 획득하면 잠금을 소유 한 스레드가이를 해제 할 때까지 다른 스레드가 잠긴 데이터에 액세스 할 수 없습니다.

모니터

JVM은 모니터 와 함께 잠금을 사용 합니다 . 모니터는 기본적으로 코드 시퀀스를 감시하여 한 번에 하나의 스레드 만 코드를 실행하도록한다는 점에서 보호자입니다.

각 모니터는 개체 참조와 연결됩니다. 스레드가 모니터의 감시 아래있는 코드 블록의 첫 번째 명령에 도달하면 스레드는 참조 된 개체에 대한 잠금을 얻어야합니다. 스레드는 잠금을 얻을 때까지 코드를 실행할 수 없습니다. 잠금을 획득하면 스레드는 보호 된 코드 블록에 들어갑니다.

스레드가 블록을 떠날 때 블록을 떠나는 방법에 관계없이 연관된 객체에 대한 잠금을 해제합니다.

다중 잠금

단일 스레드는 동일한 객체를 여러 번 잠글 수 있습니다. 각 객체에 대해 JVM은 객체가 잠긴 횟수를 유지합니다. 잠금 해제 된 개체의 개수는 0입니다. 스레드가 처음으로 잠금을 획득하면 카운트가 1로 증가합니다. 스레드가 동일한 객체에 대한 잠금을 획득 할 때마다 개수가 증가합니다. 스레드가 잠금을 해제 할 때마다 개수가 감소합니다. 카운트가 0에 도달하면 잠금이 해제되고 다른 스레드에서 사용할 수 있습니다.

동기화 된 블록

In Java language terminology, the coordination of multiple threads that must access shared data is called synchronization. The language provides two built-in ways to synchronize access to data: with synchronized statements or synchronized methods.

Synchronized statements

To create a synchronized statement, you use the synchronized keyword with an expression that evaluates to an object reference, as in the reverseOrder() method below:

class KitchenSync { private int[] intArray = new int[10]; void reverseOrder() { synchronized (this) { int halfWay = intArray.length / 2; for (int i = 0; i < halfWay; ++i) { int upperIndex = intArray.length - 1 - i; int save = intArray[upperIndex]; intArray[upperIndex] = intArray[i]; intArray[i] = save; } } } }

In the case above, the statements contained within the synchronized block will not be executed until a lock is acquired on the current object (this). If instead of a this reference, the expression yielded a reference to another object, the lock associated with that object would be acquired before the thread continued.

Two opcodes, monitorenter and monitorexit, are used for synchronization blocks within methods, as shown in the table below.

Table 1. Monitors

Opcode Operand(s) Description
monitorenter none pop objectref, acquire the lock associated with objectref
monitorexit none pop objectref, release the lock associated with objectref

When monitorenter is encountered by the Java virtual machine, it acquires the lock for the object referred to by objectref on the stack. If the thread already owns the lock for that object, a count is incremented. Each time monitorexit is executed for the thread on the object, the count is decremented. When the count reaches zero, the monitor is released.

Take a look at the bytecode sequence generated by the reverseOrder() method of the KitchenSync class.

Note that a catch clause ensures the locked object will be unlocked even if an exception is thrown from within the synchronized block. No matter how the synchronized block is exited, the object lock acquired when the thread entered the block definitely will be released.

Synchronized methods

To synchronize an entire method, you just include the synchronized keyword as one of the method qualifiers, as in:

class HeatSync { private int[] intArray = new int[10]; synchronized void reverseOrder() { int halfWay = intArray.length / 2; for (int i = 0; i < halfWay; ++i) { int upperIndex = intArray.length - 1 - i; int save = intArray[upperIndex]; intArray[upperIndex] = intArray[i]; intArray[i] = save; } } }

The JVM does not use any special opcodes to invoke or return from synchronized methods. When the JVM resolves the symbolic reference to a method, it determines whether the method is synchronized. If it is, the JVM acquires a lock before invoking the method. For an instance method, the JVM acquires the lock associated with the object upon which the method is being invoked. For a class method, it acquires the lock associated with the class to which the method belongs. After a synchronized method completes, whether it completes by returning or by throwing an exception, the lock is released.

Coming next month

Now that I have gone through the entire bytecode instruction set, I will be broadening the scope of this column to include various aspects or applications of Java technology, not just the Java virtual machine. Next month, I'll begin a multi-part series that gives an in-depth overview of Java's security model.

Bill Venners는 12 년 동안 전문적으로 소프트웨어를 작성해 왔습니다. 실리콘 밸리에 기반을 둔 그는 Artima Software Company라는 이름으로 소프트웨어 컨설팅 및 교육 서비스를 제공합니다. 수년에 걸쳐 그는 가전, 교육, 반도체 및 생명 보험 산업을위한 소프트웨어를 개발했습니다. 그는 다양한 마이크로 프로세서의 어셈블리 언어, Unix의 C, Windows의 C ++, 웹의 Java 등 다양한 플랫폼에서 다양한 언어로 프로그래밍했습니다. 그는 McGraw-Hill에서 출판 한 Inside the Java Virtual Machine이라는 책의 저자입니다.

이 주제에 대해 더 알아보기

  • The book The Java virtual machine Specification (//www.aw.com/cp/lindholm-yellin.html), by Tim Lindholm and Frank Yellin (ISBN 0-201-63452-X), part of The Java Series (//www.aw.com/cp/javaseries.html), from Addison-Wesley, is the definitive Java virtual machine reference.
  • Previous "Under The Hood" articles:
  • "The Lean, Mean Virtual Machine" Gives an introduction to the Java virtual machine.
  • "The Java Class File Lifestyle" Gives an overview to the Java class file, the file format into which all Java programs are compiled.
  • "Java's Garbage-Collected Heap" Gives an overview of garbage collection in general and the garbage-collected heap of the Java virtual machine in particular.
  • "Bytecode Basics" Introduces the bytecodes of the Java virtual machine, and discusses primitive types, conversion operations, and stack operations in particular.
  • "Floating Point Arithmetic" Describes the Java virtual machine's floating-point support and the bytecodes that perform floating point operations.
  • "Logic and Arithmetic" Describes the Java virtual machine's support for logical and integer arithmetic, and the related bytecodes.
  • "Objects and Arrays" Describes how the Java virtual machine deals with objects and arrays, and discusses the relevant bytecodes.
  • "Exceptions" Describes how the Java virtual machine deals with exceptions, and discusses the relevant bytecodes.
  • "Try-Finally"Java 가상 머신이 try-finally 절을 구현하는 방법을 설명하고 관련 바이트 코드에 대해 설명합니다.
  • "제어 흐름"Java 가상 머신이 제어 흐름을 구현하는 방법을 설명하고 관련 바이트 코드를 설명합니다.
  • "Aglets의 아키텍처"IBM의 자율적 인 Java 기반 소프트웨어 에이전트 기술인 Aglets의 내부 작동에 대해 설명합니다.
  • "The Point of Aglets"IBM의 자율적 인 Java 기반 소프트웨어 에이전트 기술인 Aglets와 같은 모바일 에이전트의 실제 유틸리티를 분석합니다.
  • "메소드 호출 및 리턴"Java 가상 머신이 관련 바이트 코드를 포함하여 메소드에서 호출하고 리턴하는 방법을 설명합니다.

이 이야기 "Java 가상 머신이 스레드 동기화를 수행하는 방법"은 원래 JavaWorld에 의해 출판되었습니다.