Java의 스레드 안전 지연 초기화
- Java의 객체 초기화
- Java에서 지연 초기화 구현
-
Java에서 스레드 안전 지연 초기화를 위한
synchronized
방법 사용 - Java에서 스레드로부터 안전한 지연 초기화를 위해 이중 확인 잠금 방법 사용
이 기사에서는 Java에서 스레드 안전 지연 초기화 구현에 대해 설명합니다.
Java의 객체 초기화
지연 초기화는 객체 생성을 지연시키는 행위입니다. 또한 처음으로 일부 계산 작업이나 비용이 많이 드는 프로세스에서 지연이 발생할 수 있습니다.
Java에는 두 가지 유형의 개체 초기화가 있습니다. Eager 초기화와 Lazy 초기화가 있습니다.
개체 초기화는 Eager 초기화에서 컴파일 시간 동안 발생합니다. 긴 프로세스의 경우 시간과 메모리를 많이 소모합니다.
지연 초기화에서 개체 초기화는 프로그램에서 필요할 때 발생합니다. 따라서 메모리를 절약하고 처리 능력을 높이며 효율성을 향상시킵니다.
스레드는 시간을 최적화하기 위해 프로세스를 병렬로 실행할 수 있는 보조 구성 요소입니다. Thread Safe
는 동시에 여러 스레드 호출 중에 함수가 반환하는 클래스의 내부 상태 및 값의 정확성을 보장하는 Java 클래스입니다.
Java에서 지연 초기화 구현
getter 메서드는 개인 멤버에 이미 어떤 값이 있는지 확인합니다. 있는 경우 함수는 이를 반환합니다. 그렇지 않으면 새 인스턴스를 만들고 처음 실행 시 반환합니다.
지연 초기화를 수행하는 방법에는 두 가지가 있습니다.
- 함수 이름 앞에
synchronize
키워드를 사용하십시오. - 이중 확인 잠금 또는 동기화 차단 방법을 사용하십시오.
Java에서 지연 초기화를 위한 스레드 안전 코드 작성
여러 스레드가 병렬로 실행될 때 변수가 예기치 않은 결과를 반환할 수 있습니다. 여기에서 Java의 교착 상태를 방지하기 위해 스레드 안전
코드가 필요합니다.
예:
토큰 배포에 사용할 수 있는 토큰 카운터가 하나만 있는 은행을 고려하십시오. 여기서 작업은 고객이 들어올 때만 은행
클래스를 만드는 것입니다. 프로세스는 게으른 초기화입니다.
다중 스레드 호출을 이해하기 위해 t1
, t2
등과 같은 다중 스레드를 생성해 보겠습니다. 각 스레드는 고객이 됩니다.
고객이 토큰을 찾으러 오면 Bank
개체를 만들고 함수 인수의 토큰 번호로 operation()
을 호출합니다. 이제 토큰을 사용할 수 있는지 여부를 표시하고 메시지에서 다음 작업을 지정합니다.
토큰을 사용할 수 있으면 토큰을 발행하십시오. 그렇지 않으면 다음 고객에게 진행합니다.
프로그램은 getInstanceSynchronizedWay()
와 getInstanceSynchronizedBlockWay()
를 모두 설명합니다. 출력 정확도를 보장하기 위해 Thread.sleep
을 사용할 수 있습니다.
Java에서 스레드 안전 지연 초기화를 위한 synchronized
방법 사용
이 예에는 두 개의 고객 스레드가 있습니다.
_instance
변수는 인스턴스가 null인지 확인합니다. 변수가 null이면 프로그램이 인스턴스를 만듭니다.
빈 플래그는 토큰이 사용 가능한지 여부를 확인합니다. 토큰을 사용할 수 있으면 플래그 값은 true입니다.
고객에게 토큰을 제공한 후 프로그램은 플래그 값을 false로 설정합니다. 따라서 다음 고객은 operation()
이 완료될 때까지 토큰을 받지 못합니다.
예제 코드:
// Helper class as a Singleton Class
class BankOperation {
// Private variables
private static BankOperation _instance;
private boolean empty = false;
private String customerName = "default";
// Displays the instance only during creation
private BankOperation() {
System.out.println("Instance Creation Over\n");
}
// synchronized method
public static synchronized BankOperation getInstanceSynchronizedWay() {
if (_instance == null)
_instance = new BankOperation();
return _instance;
}
// Check if the token is available
public boolean isOperationBankEmpty() {
return empty;
}
// When token giving is successful
public void endOperation() {
empty = true;
}
// Multiple threads access the method below
public synchronized void operation(String paramCust) {
// When the token is available. The flag is true.
if (empty == true) {
customerName = paramCust;
// Issue the token to the customer
System.out.println("Operation - Token is available.\n"
+ "Giving token to - " + customerName);
empty = false;
}
// The token is not available
else {
System.out.println("Sorry " + paramCust + ", Counter closed with " + customerName);
}
}
}
// Main class
public class Bank {
// Driver function
public static void main(String args[]) {
// synchronized method
// Create a thread in main()
Thread t1 = new Thread(new Runnable() {
// run() for thread 1
public void run() {
// Create objects of other classes here
BankOperation i1 = BankOperation.getInstanceSynchronizedWay();
System.out.println("Synchronized Method - Instance 1 - " + i1 + "\n");
// The method with an argument
i1.endOperation();
i1.operation("Customer 1");
}
});
// Thread 2
Thread t2 = new Thread(new Runnable() {
// run() for thread 2
public void run() {
BankOperation i2 = BankOperation.getInstanceSynchronizedWay();
System.out.println("Synchronized Method - Instance 2 - " + i2 + "\n");
i2.operation("Customer 2");
}
});
// Starting thread 1
t1.start();
// Start thread 2
t2.start();
}
}
출력:
Instance Creation Over
Synchronized Method - Instance 1 - BankOperation@792bbbb1
Synchronized Method - Instance 2 - BankOperation@792bbbb1
Operation - Token is available.
Giving the token to - Customer 1
Sorry Customer 2, Counter closed with Customer 1
위의 출력에서 사용자는 두 개의 고객 인스턴스가 병렬로 제공되는 것을 관찰할 수 있습니다. 따라서 첫 번째 인스턴스는 토큰을 받고 두 번째 인스턴스는 메시지를 받습니다.
Java에서 스레드로부터 안전한 지연 초기화를 위해 이중 확인 잠금 방법 사용
이 예에서는 두 개의 고객 스레드를 생성합니다. _instanceForDoubleCheckLocking
변수는 인스턴스가 null인지 여부를 두 번 확인하고 getInstanceSynchronizedBlockWay()
메서드는 새 인스턴스를 반환합니다.
비어 있음
플래그의 값은 토큰 가용성을 결정합니다. 플래그가 true이면 고객이 토큰을 사용할 수 있습니다.
고객이 토큰을 받은 후 플래그는 false가 됩니다. 여러 스레드를 실행하면 현재 스레드가 작업을 완료할 때까지 값을 변경할 수 없습니다.
예제 코드:
// Helper class
class BankOperation {
// Private variable declaration
private static BankOperation _instanceForDoubleCheckLocking;
private boolean empty = false;
private String customerName = "default";
private BankOperation() {
System.out.println("Instance Creation Over\n");
}
// Synchronized Block Method or Double-Checked Locking
public static BankOperation getInstanceSynchronizedBlockWay() {
// Check double locking
if (_instanceForDoubleCheckLocking == null)
synchronized (BankOperation.class) {
if (_instanceForDoubleCheckLocking == null)
_instanceForDoubleCheckLocking = new BankOperation();
}
return _instanceForDoubleCheckLocking;
}
// The `token` availability check
public boolean isOperationBankEmpty() {
return empty;
}
// After giving the token set the flag value
public void endOperation() {
empty = true;
}
// Multiple threads access the method below
public synchronized void operation(String paramCust) {
// The flag is true when the `token` is available
if (empty == true) {
customerName = paramCust;
// Give the `token` to the customer
System.out.println("Operation - Token is available.\n"
+ "Giving token to - " + customerName);
empty = false;
}
// When the `Token` is not available
else {
System.out.println("Sorry " + paramCust + ", Counter closed with " + customerName);
}
}
}
// Main class
public class Bank {
// Driver function
public static void main(String args[]) {
// Double Checked Locking
System.out.println("Double Checked locking - Synchronized Block");
// Thread 3
Thread t3 = new Thread(new Runnable() {
// run() for thread 3
public void run() {
BankOperation i1 = BankOperation.getInstanceSynchronizedBlockWay();
System.out.println("Double Checked Locking - Instance 1 - " + i1 + "\n");
i1.endOperation();
i1.operation("Customer 1");
}
});
// Thread 4
Thread t4 = new Thread(new Runnable() {
// run() for thread 4
public void run() {
BankOperation i2 = BankOperation.getInstanceSynchronizedBlockWay();
System.out.println("Double Checked Locking - Instance 2 - " + i2 + "\n");
i2.operation("Customer 2");
}
});
t3.start();
t4.start();
}
}
출력 1:
Double Checked locking - Synchronized Block
Instance Creation Over
Double Checked Locking - Instance 1 - BankOperation@1efc89d6
Double Checked Locking - Instance 2 - BankOperation@1efc89d6
Operation - Token is available.
Giving token to - Customer 1
Sorry Customer 2, Counter closed with Customer 1
두 고객 인스턴스가 병렬로 도착하면 프로그램이 첫 번째 인스턴스에 토큰을 제공하고 두 번째 고객에게 알립니다.
출력 2:
Double Checked locking - Synchronized Block
Instance Creation Over
Double Checked Locking - Instance 2 - BankOperation@282416b6
Double Checked Locking - Instance 1 - BankOperation@282416b6
Sorry Customer 2, the counter closed with the default
Operation - Token is available.
Giving Bank token to - Customer 1
여기서 고객 2는 토큰을 사용할 수 없으며 그 이유는 operation()
이전에 endOperation()
이 누락되었기 때문입니다. 고객 1은 endOperation()
이 operation()
이전에 실행되기 때문에 토큰을 얻습니다.
이 자습서에서는 Java에서 스레드로부터 안전한 지연 초기화를 구현하는 두 가지 방법을 배웠습니다. 첫 번째 방법은 synchronized
키워드를 사용하고 두 번째 옵션은 동기화된 차단 방법입니다.
동기화된 차단 방법은 이중 확인을 보장합니다. 사용자는 컨텍스트에 따라 한 가지 방법을 선택할 수 있습니다.