단일 모드 스 레 드 안전 실험
비 스 레 드 안전 사례 - 게으름뱅이 식
public class SingletonLazy {
private static SingletonLazy singleton = null;
private static int counter = 0;
private SingletonLazy() {
counter++;
System.out.println(String.format(" [%s] , [%d] ", Thread.currentThread().getName(), counter));
}
public static SingletonLazy getInstance() {
if (singleton == null) {
singleton = new SingletonLazy();
}
return singleton;
}
}
그렇다면, 우 리 는 그것 이 라인 이 안전 한 지 어떻게 압 니까?그 다음 에 우 리 는 Runnable 을 사용 하여 10 개의 스 레 드 를 만 들 고 구조 기 가 몇 번 호출 되 었 는 지 관찰 합 니 다.여러 번 호출 되면 자 연 스 럽 게 여러 개의 대상 을 만 들 었 습 니 다. 바로 스 레 드 가 안전 하지 않 습 니 다.
public class SingleTonApplication {
/**
* 。
* @param args
*/
public static void main(String[] args) {
//
Runnable runnable = new Runnable() {
@Override
public void run() {
SingletonLazy singletonLazy = SingletonLazy.getInstance();
System.out.println(String.format("[%s] :%s", Thread.currentThread().getName(), singletonLazy.toString()));
}
};
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(runnable);
thread.start();
}// end for
}// end main
}
출력 결 과 는 다음 과 같 습 니 다.
스 레 드 [Thread - 7] 호출 구조 기, 대상 은 [8] 차 스 레 드 [Thread - 3] 호출 구조 기, 대상 은 [3] 차 스 레 드 [Thread - 1] 호출 구조 기, 대상 은 [4] 차 스 레 드 [Thread - 6] 호출 구조 기, 대상 은 [7] 차 스 레 드 [Thread - 2] 호출 구조 기, 대상 은 [2] 차 스 레 드 [Thread - 4] 호출 구조 기, 대상 은 [5] 차 스 레 드 를 만 들 었 습 니 다.[Thread - 0] 호출 구조 기, 대상 생 성 [2] 차 스 레 드 [Thread - 5] 호출 구조 기, 대상 생 성 [6] 차 스 레 드 [Thread - 9] 호출 구조 기, 대상 생 성 [10] 회 [Thread - 0] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@2116aeb스 레 드 [Thread - 8] 호출 구조 기, 대상 생 성 [9] 회 [Thread - 4]스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@2eac0b4[Thread - 2] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@1c2bd9d7[Thread - 6] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@4bcf6203[Thread - 1] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@475f7458 [Thread-3]스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@46d8dc2e[Thread - 7] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@44fd2254[Thread - 8] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@4268d15[Thread - 5] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@45826b5c [Thread-9]스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@755688aa
이 를 통 해 알 수 있 듯 이 여러 스 레 드 가 CPU 자원 을 경쟁 할 때 하나의 인 스 턴 스 를 만 들 었 습 니 다. 이 실험 을 통 해 이 사례 는 스 레 드 가 안전 하지 않 습 니 다. 그래서 우 리 는
getInstance
방법 에 synchronized
키 워드 를 추가 합 니 다.public static synchronized SingletonLazy getInstance() {...}
출력 은 다음 과 같 습 니 다:
스 레 드 [Thread - 8] 호출 구조 기, 대상 생 성 [1] 회 [Thread - 2] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 4] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 5] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33 [Thread-8]스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 3] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 9] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 0] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33 [Thread-1]스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 6] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33[Thread - 7] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazy.SingletonLazy@48c85a33 Process finished with exit code 0
CPU 자원 을 빼 앗 아 유일한 인 스 턴 스 를 만 든 스 레 드
[Thread-8]
를 볼 수 있 습 니 다. 이 때 스 레 드 안전 문제 가 해결 되 었 습 니 다. 그러나 새로운 문 제 를 일 으 켰 습 니 다. 여러 스 레 드 가 거의 동시에 접근 getInstance
하 는 방법 이 있 을 때 여러 스 레 드 가 순서대로 방 법 에 들 어가 야 합 니 다. 이 로 인해 여러 스 레 드 가 임계 구역 (잠 겨 있 는 코드 블록) 에 들 어 갈 때 까지 기 다 려 야 합 니 다.시간. 우 리 는 getInstance
방법 에 sleep()
을 추가 하여 임계 구역 에 들 어 가 는 스 레 드 를 잠시 기다 리 게 합 니 다. 아 날로 그 대상 이 대상 을 얻 을 때 걸 리 는 시간, 개 조 된 코드 는 다음 과 같 습 니 다.스 레 드 안전 사례 - 게으름뱅이 식
public class Singleton {
private static Singleton singleton = null;
private static int counter = 0;
private Singleton() {
counter++;
System.out.println(String.format(" [%d] ", counter));
}
/**
* getInstance , ,
* ( ) 。
* @return
*/
public static synchronized Singleton getInstance() {
// start
try {
System.out.println(String.format("[%s] 1 ", Thread.currentThread().getName()));
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// end
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
현재, 우 리 는
CountDownLatch
클래스 를 통 해 main 메 인 스 레 드 가 모든 하위 스 레 드 실행 이 끝 날 때 까지 기다 린 다음 에 10 번 의 대상 인 스 턴 스 를 얻 는 데 걸 리 는 시간 을 통계 해 야 합 니 다.public class SingleTonApplication {
public static void main(String[] args) throws InterruptedException {
int createTimes = 10;
final CountDownLatch latch = new CountDownLatch(createTimes);
//
Runnable runnable = new Runnable() {
@Override
public void run() {
Singleton singleton = Singleton.getInstance();
System.out.println(String.format("[%s] :%s", Thread.currentThread().getName(), singleton.toString()));
latch.countDown();
}
};
long start = System.currentTimeMillis();
for (int i = 0; i < createTimes; i++) {
Thread thread = new Thread(runnable);
thread.start();
}// end for
latch.await(); //
System.out.println(String.format(" [%d] :[%dms]", createTimes, (System.currentTimeMillis() - start)));
}// end main
}
출력 은 다음 과 같 습 니 다:
[Thread - 5] 대상 인 스 턴 스 를 가 져 와 1 초 동안 구조 대상 이 호출 될 때 까지 기 다 립 니 다. [Thread - 9] 대상 인 스 턴 스 를 가 져 와 1 초 동안 기 다 립 니 다. [Thread - 5] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 8] 대상 인 스 턴 스 를 가 져 와 1 초 동안 기 다 립 니 다. [Thread - 9] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848 [Thread-7]대상 인 스 턴 스 를 가 져 와 1 초 기다 리 기 [Thread - 8] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 6] 대상 인 스 턴 스 를 가 져 와 1 초 를 기 다 립 니 다. [Thread - 7] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 1] 대상 인 스 턴 스 가 져 오기 1 초 대기 [Thread - 6]스 레 드 인쇄 현재 대상: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 2] 대상 인 스 턴 스 를 가 져 와 1 초 를 기 다 립 니 다. [Thread - 1] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 4] 대상 인 스 턴 스 를 가 져 와 1 초 동안 기 다 립 니 다. [Thread - 2] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848 [Thread-3]대상 인 스 턴 스 를 가 져 와 1 초 를 기 다 립 니 다. [Thread - 4] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 0] 대상 인 스 턴 스 를 가 져 와 1 초 동안 기 다 립 니 다. [Thread - 3] 스 레 드 는 현재 대상 을 인쇄 합 니 다: com. hua. singleton. lazythreadsafe.Singleton@b07848[Thread - 0] 스 레 드 인쇄 현재 대상: com. hua. singleton. lazythreadsafe.Singleton@b07848대상 가 져 오기 [10]회 소모 시간: [10052 ms]
출력 로그 에 따 르 면 모든 스 레 드 는 인 스 턴 스 를 가 져 올 때 일정한 시간 을 기 다 려 야 합 니 다. 다 중 스 레 드 의 장점 은 발휘 되 지 않 았 습 니 다. 사실 우 리 는 대상 을 만 들 때 동기 화 를 해 야 합 니 다. 따라서 이중 검증 잠 금 의 단일 생 성 모드 를 도입 합 니 다.
스 레 드 안전, 시간 소모 가 적은 단일 예 - 이중 검사 잠 금
public class SingletonDCL {
private volatile static SingletonDCL singleton;
private static int counter = 0;
private SingletonDCL() {
counter++;
System.out.println(String.format(" [%d] ", counter));
}
/**
* ( ) ,
* ,
* "lazythreadsafe" , ,
* @return
*/
public static SingletonDCL getInstance() {
// start
try {
System.out.println(String.format("[%s] 1 ", Thread.currentThread().getName()));
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// end
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new SingletonDCL();
}// end if
}// end syn
}// end if
return singleton;
}
}
실험 코드:
public class SingleTonApplication {
public static void main(String[] args) throws InterruptedException {
int createTimes = 10;
final CountDownLatch latch = new CountDownLatch(createTimes);
//
Runnable runnable = new Runnable() {
@Override
public void run() {
SingletonDCL singleton = SingletonDCL.getInstance();
System.out.println(String.format("[%s] :%s", Thread.currentThread().getName(), singleton.toString()));
latch.countDown(); // count 1
}
};
long start = System.currentTimeMillis();
for (int i = 0; i < createTimes; i++) {
Thread thread = new Thread(runnable);
thread.start();
}// end for
//
latch.await();
System.out.println(String.format(" [%d] :[%dms]", createTimes, (System.currentTimeMillis() - start)));
}// end main
}
콘 솔 출력:
[Thread - 9] 대상 인 스 턴 스 1 초 대기 [Thread - 6] 대상 인 스 턴 스 1 초 대기 [Thread - 1] 대상 인 스 턴 스 1 초 대기 [Thread - 7] 대상 인 스 턴 스 1 초 대기 [Thread - 2] 대상 인 스 턴 스 1 초 대기 [Thread - 3] 대상 인 스 턴 스 1 초 대기 [Thread - 5] 대상 인 스 턴 스 1 초 대기 [Thread - 8] 대상 인 스 턴 스 1 초 대기 [Thread - 0]대상 인 스 턴 스 가 져 오기 1 초 대기 [Thread - 4] 대상 인 스 턴 스 가 져 오기 1 초 대기 구조 대상 이 호출 [1] 회 [Thread - 1] 스 레 드 로 현재 대상 인쇄: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 2] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 3] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166 [Thread-6]스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 9] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 8] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 5] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166 [Thread-7]스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 0] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166[Thread - 4] 스 레 드 인쇄 현재 대상: com. hua. singleton. dcl.SingletonDCL@7115e166획득 대상 [10] 회 소모 시간: [1031 ms]
기다 리 는 동안 여러 스 레 드 가 동시에
getInstance
방법 으로 들 어 가 는 것 을 볼 수 있 습 니 다. 그 다음 에 먼저 한 번 검사 singleton
합 니 다.생 성 되 었 는 지, 생 성 되 었 는 지, 바로 되 돌 립 니 다. 생 성 되 지 않 았 다 면 동기 코드 블록 에 들 어 갑 니 다. 동기 코드 블록 에서 singleton 대상 이 있 는 지 다시 한 번 판단 하고 있 으 면 처리 하지 않 습 니 다. 없 을 때 만 들 었 습 니 다. 이 럴 때 동기 코드 블록 에서 도 판단 해 야 하 는 이 유 를 묻 는 친구 가 있 을 수 있 습 니 다 if (singleton == null)
.여러 스 레 드 가 동시에 getInstance
방법 으로 가 는 것 을 상상 할 수 있 습 니 다. 이 때 동기 코드 블록 에 singleton 이 아직 만 들 어 지지 않 았 습 니 다. 판단 하지 않 으 면 프로그램 은 여기 서 인 스 턴 스 를 만들어 야 한다 고 생각 합 니 다. 그러면 여러 개의 인 스 턴 스 가 생 성 될 것 입 니 다. 우리 의 단일 모드 는 자 연 스 럽 게 작 동 하지 않 습 니 다.총결산
이중 검사 잠 금 식 의 단일 모드 스 레 드 가 안전 하고 나중에 스 레 드 가 먼저 대상 을 만 든 후에 도 임계 구역 에서 물 러 나 지 않 은 상태 에서 기다 리 는 것 을 피 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.