Java에서 키워드 동기화 된 키워드는 스레드 동기화 제어에 사용하여 주요 리소스에 대한 순차적 액세스를 달성하고 다중 스레드 동시 실행으로 인한 데이터 불일치를 피할 수 있습니다. 동기화 된 원리는 객체 모니터 (잠금)입니다. 모니터를 얻는 스레드 만 계속 실행할 수 있습니다. 그렇지 않으면 스레드가 모니터를 얻기 위해 대기합니다. Java의 각 객체 또는 클래스에는 그와 관련된 잠금 장치가 있습니다. 객체의 경우이 객체의 인스턴스 변수를 모니터링합니다. 클래스의 경우 클래스 변수를 모니터링합니다 (클래스 자체는 클래스 클래스의 객체이므로 클래스와 관련된 잠금 장치도 객체 잠금입니다). 동기화 된 키워드를 사용하는 두 가지 방법은 동기화 된 메소드 및 동기화 된 블록입니다. 두 모니터링 영역 모두 소개 된 객체와 관련이 있습니다. 이 모니터링 영역에 도달하면 JVM은 참조 객체를 잠그고 떠나면 참조 객체의 잠금이 해제됩니다 (JVM은 예외 종료가있을 때 잠금을 해제합니다). 객체 잠금은 JVM의 내부 메커니즘입니다. 동기화 방법 또는 동기화 블록 만 작성하면됩니다. 모니터링 영역을 작동 할 때 JVM은 자동으로 잠금을 획득하거나 해제합니다.
예 1
먼저 첫 번째 예를 살펴 보겠습니다. Java에는 동시에 동시에 액세스 할 수있는 동일한 객체의 임계 영역이 하나뿐입니다 (모든 비 정적 동기화 된 방법) :
패키지 동시성; 공개 클래스 Main8 {public static void main (String [] args) {계정 계정 = 새 계정 (); 계정 .setBalance (1000); 회사 회사 = 새로운 회사 (계정); Thread CompanyThread = 새로운 스레드 (회사); 은행 = 새로운 은행 (계정); 스레드 뱅크 스레드 = 새 스레드 (은행); System.out.printf ( "계정 : 초기 잔액 : %f/n", account.getBalance ()); CompanyThread.start (); bankthread.start (); try {// join () 메소드 가이 두 스레드가 대기하여 companythread.join (); bankthread.join (); System.out.printf ( "계정 : 최종 잔액 : %f/n", account.getBalance ()); } catch (InterruptedException e) {e.printstacktrace (); }}} /*계정*/클래스 계정 {개인 이중 잔액; /*균형 균형을 유지하기 위해 들어오는 데이터 추가*/ public synchronized void addAmount (double fumer) {double tmp = 밸런스; try {thread.sleep (10); } catch (InterruptedException e) {e.printstacktrace (); } tmp += 금액; 밸런스 = TMP; } /*균형 균형에서 들어오는 데이터 공제* / public synchronized void suxtamount (이중 금액) {double tmp = 밸런스; try {thread.sleep (10); } catch (InterruptedException e) {e.printstacktrace (); } tmp- = 금액; 밸런스 = TMP; } public double getBalance () {return Balance; } public void setBalance (Double Balance) {this.balance = 밸런스; }} /*은행*/클래스 은행은 실행 가능한 {개인 계정 계정; 공공 은행 (계정 계정) {this.account = 계정; } @override public void run () {for (int i = 0; i <100; i ++) {ac }}} /*회사*/클래스 회사는 실행 가능한 {개인 계정 계정; 공개 회사 (계정 계정) {this.account = 계정; } @override public void run () {for (int i = 0; i <100; i ++) {account.addamount (1000); }}}잔액을 차단하고 공제 할 수있는 은행 계좌에 대한 시뮬레이션 응용 프로그램을 개발했습니다. 이 프로그램은 addamount () 메소드를 100 번 호출하여 매번 1,000을 입금하여 계정을 재충전합니다. 그런 다음 SuptractAmount () 메소드를 100 회 호출하여 계정 잔액을 공제하여 매번 1,000을 공제합니다. 계정의 최종 잔액은 초기 잔액과 동일 할 것으로 예상하며 동기화 된 키워드를 통해이를 구현합니다.
공유 데이터의 동시 액세스 문제를 보려면 addAmount () 및 subtractAmount () 메소드 선언에서 동기화 된 키워드를 삭제하면됩니다. 동기화 된 키워드가 없으면 인쇄 된 균형 값이 일관되지 않습니다. 이 프로그램을 여러 번 실행하면 다른 결과를 얻을 수 있습니다. JVM은 스레드의 실행 순서를 보장하지 않기 때문에 실행할 때마다 스레드는 다른 순서로 계정 잔액을 읽고 수정하여 최종 결과가 다릅니다.
객체의 메소드는 동기화 된 키워드를 사용하여 선언되며 하나의 스레드에서만 액세스 할 수 있습니다. Thread A가 동기화 메소드 SyncMethoda ()를 실행하는 경우 스레드 B는 다른 동기화 메소드를 실행하려고합니다. 그러나 스레드 B가 동일한 클래스의 다른 객체에 액세스하면 스레드가 차단되지 않습니다.
예 2
동일한 객체에서 정적 동기화 된 방법과 비 정적 동기화 된 메소드가 동시에 여러 스레드로 액세스 할 수 있다는 문제를 보여줍니다. 확인하십시오.
패키지 동시성; 공개 클래스 Main8 {public static void main (String [] args) {계정 계정 = 새 계정 (); 계정 .setBalance (1000); 회사 회사 = 새로운 회사 (계정); Thread CompanyThread = 새로운 스레드 (회사); 은행 = 새로운 은행 (계정); 스레드 뱅크 스레드 = 새 스레드 (은행); System.out.printf ( "계정 : 초기 잔액 : %f/n", account.getBalance ()); CompanyThread.start (); bankthread.start (); try {// join () 메소드 가이 두 스레드가 대기하여 companythread.join (); bankthread.join (); System.out.printf ( "계정 : 최종 잔액 : %f/n", account.getBalance ()); } catch (InterruptedException e) {e.printstacktrace (); }}} /*계정*/클래스 계정 {/*여기에서 정적 변수로 변경*/private static double balance = 0; /*밸런스 밸런스에 들어오는 데이터 추가, 정적*/ public static synchronized void addamount (double fumer) {double tmp = balance; try {thread.sleep (10); } catch (InterruptedException e) {e.printstacktrace (); } tmp += 금액; 밸런스 = TMP; } /*밸런스 밸런스에서 들어오는 데이터를 공제* / 공개 동기화 된 void suxtamount (이중 금액) {double tmp = balance; try {thread.sleep (10); } catch (InterruptedException e) {e.printstacktrace (); } tmp- = 금액; 밸런스 = TMP; } public double getBalance () {return Balance; } public void setBalance (Double Balance) {this.balance = 밸런스; }} /*은행*/클래스 은행은 실행 가능한 {개인 계정 계정; 공공 은행 (계정 계정) {this.account = 계정; } @override public void run () {for (int i = 0; i <100; i ++) {ac }}} /*회사*/클래스 회사는 실행 가능한 {개인 계정 계정; 공개 회사 (계정 계정) {this.account = 계정; } @override public void run () {for (int i = 0; i <100; i ++) {account.addamount (1000); }}}방금 정적 키워드를 추가하여 이전 예제에서 균형을 수정했으며 addamount () 메소드는 정적 키워드를 수정할 수도 있습니다. 실행 결과를 직접 테스트 할 수 있으며 각 실행은 다른 결과를 얻을 수 있습니다!
일부 요약 :