게임 자바 강의 - 자바 스 레 드 동기 화 (1)


동시 프로 그래 밍 에서 여러 개의 실행 스 레 드 가 자원 을 공유 하 는 문제 에 자주 부 딪 힐 수 있다.예 를 들 어 여러 스 레 드 가 동시에 파일 을 읽 고 쓰기, 공용 데이터베이스 연결, 전역 카운터 등 이다.많은 스 레 드 간 의 동기 화 문 제 를 처리 하지 않 으 면 상태 가 일치 하지 않 거나 다른 오 류 를 일 으 키 기 쉽다.
   동기 화 는 하나의 스 레 드 가 대상 이 일치 하지 않 는 상 태 를 보 는 것 을 막 을 수 있 을 뿐만 아니 라 동기 화 방법 이나 블록 에 들 어 가 는 모든 스 레 드 를 확보 할 수 있 으 며 같은 자물쇠 로 보호 되 기 전의 모든 수정 결 과 를 볼 수 있다.동기 화 를 처리 하 는 관건 은 임계 조건 (critical section), 즉 다 중 스 레 드 접근 / 공유 자원 의 코드 블록 을 정확하게 식별 하 는 것 이다.
  키워드 synchronized 는 같은 시간 을 보장 할 수 있 습 니 다. 하나의 스 레 드 만 이 특정한 방법 이나 코드 블록 을 실행 할 수 있 습 니 다.또한 자바 언어 규범 은 하나의 변 수 를 읽 고 쓰 는 것 이 원자 임 을 보증 합 니 다. log 나 double 을 제외 하고 언어 규범 은 스 레 드 가 원자 데 이 터 를 읽 을 때 임의의 수 치 를 보지 못 하도록 보장 하지만 한 스 레 드 가 기록 한 값 이 다른 스 레 드 에 대해 볼 수 있 고 스 레 드 간 의 통신, 동기 화 는 필요 합 니 다.
  synchronized 동기 화 방법:
  우 리 는 synchronized 키 워드 를 방법 앞 에 두 고 하나의 스 레 드 만 이 방법 을 실행 할 수 있 도록 보장 할 수 있 습 니 다.주의해 야 할 것 은 하나의 정적 방법 과 인 스 턴 스 방법 이 synchronized 가 있다 면 한 스 레 드 가 정적 방법 에 접근 하고 다른 스 레 드 가 인 스 턴 스 방법 에 접근 하 는 것 을 허용 하 는 것 입 니 다.예 를 들 면:
 
private static synchronized void stopRequested(){  
        stopRequest = true;  
    }

 
   synchronized 방법 은 아주 짧 은 수정 이나 공유 자원 을 읽 는 것 일 뿐 이 며, 그렇지 않 으 면 성능 문 제 를 일 으 킬 수 있 습 니 다. synchronized 는 본질 적 으로 서로 배척 하기 때 문 입 니 다.
  synchronized 동기 블록:
synchronized (this) {  
// Java code  
}  

   동기 블록 은 임계 구간 만 동기 화하 고 나머지 부분 은 병행 할 수 있 습 니 다.서로 독립 된 공유 자원 에 대해 서 는 서로 다른 자물쇠 로 동기 화 할 수 있다.예 를 들 어 두 개의 영화관 표를 동시에 판매한다.  
public class Cinema {  
  
    private long vacanciesCinema1;  
    private long vacanciesCinema2;  
    private final Object controlCinema1, controlCinema2;  
  
    public Cinema() {  
        controlCinema1 = new Object();  
        controlCinema2 = new Object();  
        vacanciesCinema1 = 20;  
        vacanciesCinema2 = 20;  
    }  
  
    public boolean sellTickets1(int number) {  
        synchronized (controlCinema1) {  
            if (number < vacanciesCinema1) {  
                vacanciesCinema1 -= number;  
                return true;  
            } else {  
                return false;  
            }  
        }  
    }  
  
    public boolean sellTickets2(int number) {  
        synchronized (controlCinema2) {  
            if (number < vacanciesCinema2) {  
                vacanciesCinema2 -= number;  
                return true;  
            } else {  
                return false;  
            }  
        }  
    }  
  
}

 
   읽 기와 쓰기 primitive 형식 은 원자 이지 만 스 레 드 간 에 동기 화 되 지 않 으 면 데이터 불일치 문 제 를 일 으 킬 수 있 습 니 다. 다음 예 를 보 세 요.
 
public class TestStop {  
  
    private static boolean stopRequest;  
      
    public static void main(String[]args) throws InterruptedException{  
        Thread t = new Thread( new Runnable(){  
            public void run(){  
                int i = 0;  
                while(!stopRequest){  
                    i++;  
                }  
            }  
        });  
        t.start();  
        TimeUnit.SECONDS.sleep(2);  
        stopRequest = true;  
    }  
      
}  

 
    이 코드 는 때때로 멈 출 수 없습니다. 왜냐하면 하위 스 레 드 가 stopRequest 에 대한 변경 사항 을 보지 못 했 기 때 문 입 니 다.해결 방법 은 공유 변수 에 대한 동기 화 접근 을 추가 하 는 것 입 니 다.
   
public class TestStop {  
  
    private static boolean stopRequest;  
      
    private static synchronized void stopRequested(){  
        stopRequest = true;  
    }  
      
    private static synchronized boolean getStopRequest(){  
        return stopRequest;  
    }  
      
    public static void main(String[]args) throws InterruptedException{  
        Thread t = new Thread( new Runnable(){  
            public void run(){  
                int i = 0;  
                while(!getStopRequest()){  
                    i++;  
                }  
            }  
        });  
        t.start();  
        TimeUnit.SECONDS.sleep(2);  
        stopRequested();  
    }  
      
}  

  
읽 기와 쓰기 가 동기 화 되 지 않 으 면 동기 화 는 효과 가 없다.이 경우 volatile 로 동기 화 를 없 앨 수 있다.
    후속 장 에서 저 희 는 synchronize 와 Lock 에 관 한 내용 을 더 소개 할 것 입 니 다.

좋은 웹페이지 즐겨찾기