특별 론

자바 퍼 즐
어떤 때 는 하나의 유형 에 있어 서 만들어 진 인 스 턴 스 개 수 를 추적 하 는 것 이 매우 유용 하 다.그 전형 적 인 실현 은 구조 기 를 개인 정적 도 메 인 으로 증가 시 켜 서 이 루어 진 것 이다.다음 프로그램 에서 Creature 류 는 이러한 기 교 를 보 여 주 었 고 Creator 류 는 이 를 연습 하여 만 든 Creature 인 스 턴 스 의 수 를 출력 합 니 다.그렇다면 이 프로그램 은 무엇 을 인쇄 할 까?

public class Creator {
  public static void main(String[] args) {
    for (int i = 0; i < 100; i++)
      Creature creature = new Creature();
    System.out.println(Creature.numCreated());
  }
}
class Creature {
  private static long numCreated = 0;
  public Creature() {
    numCreated++;
  }
  public static long numCreated() {
   return numCreated;
  }
}

이것 은 사람 을 놀 리 는 문제 다.이 프로그램 은 100 을 인쇄 해 야 할 것 처럼 보이 지만,컴 파일 할 수 없 기 때문에 아무것도 인쇄 하지 않 았 다.만약 네가 그것 을 컴 파일 하려 고 시도 한다 면,컴 파일 러 의 진단 정 보 는 기본적으로 쓸모 가 없다 는 것 을 알 게 될 것 이다.다음은 자바 c 가 인쇄 한 것 입 니 다:
Creator.java:4: not a statement
Creature creature = new Creature();
^
Creator.java:4: ';' expected
Creature creature = new Creature();
^
로 컬 변수 성명 은 하나의 문구 처럼 보이 지만 기술적 으로 는 그렇지 않 습 니 다.이것 은 로 컬 변수 성명 문(local variable declaration statement)[JLS 14.4]일 것 입 니 다.자바 언어 규범 은 로 컬 변수 성명 문 구 를 for,while 또는 do 순환 에서 반복 적 으로 실행 하 는 것 을 허용 하지 않 습 니 다[JLS 14.12-14].하나의 로 컬 변수 성명 은 하나의 구문 으로 하나의 구문 블록 에 만 나타 날 수 있 습 니 다.(하나의 문장 블록 은 한 쌍 의 괄호 와 이 괄호 전에 포 함 된 문장 과 성명 으로 구성 되 어 있다.)
이 문 제 를 정정 할 수 있 는 두 가지 방법 이 있다.가장 눈 에 띄 는 방법 은 이 성명 을 하나의 어구 에 넣 는 것 이다.
for (int i = 0; i < 100; i++) {
Creature creature = new Creature();
}
그러나 이 프로그램 은 로 컬 변 수 를 사용 하지 않 았 음 을 주의 하 십시오.그래서 이 성명 을 아무것도 사용 하지 않 았 다.
새로운 생 성 대상 에 대한 인용 이 버 려 지고 있 음 을 강조 할 수 있 습 니 다.
for (int i = 0; i < 100; i++)
new Creature();
우리 가 위의 어떤 수정 을 하 든 이 프로그램 은 우리 가 원 하 는 100 을 인쇄 할 것 이다.
Creature 인 스 턴 스 개 수 를 추적 하 는 변수(numCreated)는 int 형식 이 아 닌 log 형식 입 니 다.프로그램 이 만 든 인 스 턴 스 가 int 수치의 최대 값 을 남 길 수 있다 는 것 을 쉽게 상상 할 수 있 지만,롱 수치의 최대 값 보다 많 지 는 않 습 니 다.
int 수치의 최대 치 는 231-1,즉 약 2.1 이다.×109,롱 수치의 최대 치 는 263-1,즉 약 9.2 이다.×1018。현재 초당 108 개의 대상 을 만 드 는 것 이 가능 합 니 다.이것 은 프로그램 이 log 형식의 대상 카운터 가 넘 치기 전에 약 3 천 년 동안 실행 해 야 한 다 는 것 을 의미 합 니 다.하드웨어 속도 향상 에 직면 하 더 라 도 롱 유형의 대상 계수 기 는 예측 가능 한 미래 에 대처 할 수 있어 야 한다.
또 주의해 야 할 것 은 이 수수께끼 의 생 성 계수 전략 이 라인 이 안전 한 것 이 아니 라 는 것 이다.여러 스 레 드 가 대상 을 병렬 적 으로 만 들 수 있다 면,점차 증가 하 는 카운터 의 코드 와 읽 기 카운터 의 코드 는 모두 동기 화 되 어야 합 니 다.

// Thread-safe creation counter
class Creature {
private static long numCreated;
public Creature() {
synchronized (Creature.class) {
numCreated++;
}
}
public static synchronized long numCreated() {
return numCreated;
}
}

또는 5.0 또는 업 데 이 트 된 버 전 을 사용한다 면 AtomicLong 인 스 턴 스 를 사용 할 수 있 습 니 다.동시 다발 에 직면 했 을 때 동기 화 에 대한 수 요 를 돌 릴 수 있 습 니 다.

// Thread-safe creation counter using AtomicLong;
import java.util.concurrent.atomic.AtomicLong;
class Creature {
private static AtomicLong numCreated = new AtomicLong();
public Creature() {
numCreated.incrementAndGet();
}
public static long numCreated() {
return numCreated.get();
}
}

numCreated 를 순간 적 으로 설명 하 는 것 은 문 제 를 해결 하기 에는 부족 합 니 다.volatile 수식 자 는 다른 스 레 드 가 최근 에 이 도 메 인 에 부 여 된 값 을 볼 수 있 지만 원자 적 인 증가 작업 을 할 수 없 기 때 문 입 니 다.
한 마디 로 하면 로 컬 변수 성명 은 for,while 또는 do 순환 에서 반복 되 는 실행 문 으로 사용 할 수 없습니다.하나의 문장 으로 하나의 문장 블록 에 만 나타 날 수 있 습 니 다.또한,하나의 변 수 를 사용 하여 인 스 턴 스 생 성 을 계산 할 때 int 형식의 변 수 를 사용 하여 넘 치지 않도록 해 야 합 니 다.마지막 으로 다 중 스 레 드 에 인 스 턴 스 를 만 들 려 면 인 스 턴 스 카운터 의 접근 을 동기 화하 거나 AtomicLong 형식의 계수 기 를 사용 하 십시오.

좋은 웹페이지 즐겨찾기