Java Foundation이 약하거나 Java Multithreading을 잘 이해하지 못하는 경우이 기사를 읽으십시오. "Java Multithreading의 스레드 정의, 상태 및 속성을 배우십시오"
동기화는 항상 Java 멀티 스레딩의 어려운 지점이었으며 Android 개발을 수행 할 때 거의 사용되지 않지만 동기화에 익숙하지 않은 이유는 아닙니다. 이 기사를 통해 더 많은 사람들이 Java 동기화를 이해하고 적용 할 수 있기를 바랍니다.
다중 스레드 애플리케이션에서 둘 이상의 스레드는 동일한 데이터에 대한 액세스를 공유해야합니다. 두 스레드가 동일한 객체에 액세스하고 각 스레드가 객체를 수정하는 메소드를 호출하는 경우 일반적으로 레이스 조건이됩니다.
경쟁 조건의 가장 쉬운 예는 예를 들어, 기차 티켓은 확실하지만 모든 곳에서 열차 티켓을 판매하는 창이 있으며 각 창은 하나의 스레드와 동일하며 많은 스레드가 모든 열차 티켓 자원을 공유합니다. 그리고 그것은 원자력을 보장 할 수 없습니다. 두 스레드가 시점 에서이 자원을 사용하는 경우, 꺼내는 열차 티켓은 동일합니다 (좌석 번호는 동일)이므로 승객에게 문제가 발생합니다. 솔루션은 스레드가 열차 티켓 자원을 사용하고 싶을 때 잠금 장치를 제공하고 작업을 완료 한 후이 자원을 사용하려는 다른 스레드에 잠금을 제공한다는 것입니다. 이런 식으로 위의 상황은 발생하지 않습니다.
1. 물체를 잠그십시오
동기화 된 키워드는 자동으로 잠금 및 관련 조건을 제공합니다. 명시 적 잠금이 필요한 대부분의 경우 동기화 된 사용이 매우 편리합니다. 그러나 ReintrantLock 클래스 및 조건부 객체를 이해하면 동기화 된 키워드를 더 잘 이해할 수 있습니다. 재진입 락은 Java SE 5.0에서 소개됩니다. 코드 블록의 구조는 다음과 같이 ReentrantLock을 사용하여 보호됩니다.
mlock.lock (); try {...} 마침내 {mlock.unlock ();}이 구조는 언제든지 하나의 스레드 만 중요 영역에 들어가도록합니다. 스레드가 잠금 객체를 차단하면 다른 스레드가 잠금 문을 전달할 수 없습니다. 다른 스레드가 잠금을 호출하면 첫 번째 스레드가 잠금 객체를 출시 할 때까지 차단됩니다. 마침내 잠금 해제 작업을 수행해야합니다. 임계 영역에서 예외가 발생하면 잠금이 해제되어야합니다. 그렇지 않으면 다른 스레드가 영원히 차단됩니다.
2. 조건부 객체 <br /> 임계 영역에 들어가면 특정 조건이 충족 된 후에 만 실행할 수 있습니다. 조건부 객체를 사용하여 잠금을 얻었지만 유용한 작업을 수행 할 수없는 스레드를 관리하십시오. 조건부 객체를 조건부 변수라고도합니다.
조건부 개체가 필요한 이유를 알아 보려면 다음 예를 살펴 보겠습니다.
시나리오에서 은행 양도를 사용해야한다고 가정하고 먼저 은행 클래스를 작성하고 해당 생성자를 계정 수와 계정 금액으로 전송해야합니다.
공공 클래스 은행 {private double [] 계정; 개인 자물쇠 지폐; 공공 은행 (int n, double initialbance) {concments = new double [n]; banklock = 새로운 재 렌트 런 락 (); for (int i = 0; i <ac }}}다음으로 우리는 돈을 철회하고 철수 방법을 작성하고 싶습니다. 이송자는 수신자이며 양도 금액입니다. 결과적으로, 우리는 양도자의 잔액이 충분하지 않다는 것을 알았습니다. 다른 스레드가 양도자에게 충분한 비용을 절약하면 이전이 성공할 수 있습니다. 그러나이 스레드는 독점적 인 자물쇠를 획득했으며 다른 스레드는 예금 작업을 수행하기 위해 잠금 장치를 얻을 수 없습니다. 이것이 조건부 객체를 소개 해야하는 이유입니다.
공개 무효 전송 (int from, int to, int fumber) {banklock.lock (); try {while (chants [from] <auge) {// wait}} 마침내 {banklock.unlock (); }}잠금 객체에는 여러 관련 조건 객체가 있습니다. NewCondition 방법을 사용하여 조건 객체를 얻을 수 있습니다. 조건 객체를 얻은 후에는 대기 방법을 호출하고 현재 스레드가 차단되고 잠금이 버려집니다.
공공 클래스 은행 {private double [] 계정; 개인 자물쇠 지폐; 개인 조건 조건; 공공 은행 (int n, double initialbance) {concments = new double [n]; banklock = 새로운 재 렌트 런 락 (); // 조건 객체 조건을 가져옵니다. for (int i = 0; i <ac }} public void 송장 (int from, int to, int fumber)은 InterruptedException {banklock.lock (); try {while (chants [from] <infort)) {// 현재 스레드를 차단하고 잠금 조건을 포기합니다 .await (); }} 마침내 {banklock.unlock (); }}} 잠금을 기다리는 스레드는 기본적으로 차선 방법을 호출하는 스레드와 다릅니다. 스레드가 대기 방법을 호출하면 해당 조건의 대기 세트에 들어갑니다. 잠금을 사용할 수 있으면 스레드는 즉시 잠금 해제 할 수 없지만 다른 스레드가 동일한 조건에서 신호 메소드를 호출 할 때까지 차단 상태에 있습니다. 다른 스레드가 이전 이전자에게 돈을 송금 할 준비가되면 조건을 호출하십시오 .SignalAll (); 이 호출은이 조건을 기다리는 모든 스레드를 다시 활성화합니다.
스레드가 대기 방법을 호출하면 스스로 재 활성화 할 수 없으며 다른 스레드가 SignalAll 메소드를 호출하여 스스로를 활성화하기를 희망합니다. 다른 스레드가 대기 스레드를 활성화하지 않으면 교착 상태가 발생합니다. 다른 모든 스레드가 차단되고 다른 스레드를 차단 해제하기 전에 마지막으로 활성 스레드 호출이 기다리면 차단됩니다. 스레드는 다른 스레드를 차단 해제 할 수 없으며 프로그램이 중단됩니다.
그러면 언제 신호가 호출 될까요? 일반적으로 스레드의 방향이 변경되기를 기다릴 때 SignalAll을 호출하는 것이 좋습니다. 이 예에서 계정 잔액이 변경되면 대기 스레드는 잔액을 확인할 기회가 있어야합니다.
공개 무효 전송 (int, int to, int fumber)은 InterruptedException {banklock.lock (); try {while (chants [from] <infort)) {// 현재 스레드를 차단하고 잠금 조건을 포기합니다 .await (); } // 전송 작업 ... 조건 .signalall (); } 마침내 {banklock.unlock (); }}SignalAll 메소드가 호출되면 대기 스레드가 즉시 활성화되지 않습니다. 이 스레드는 현재 스레드가 동기 메소드를 종료 한 후 경쟁하여 객체에 대한 액세스를 달성 할 수 있도록 대기 스레드를 차단 해제합니다. 다른 방법은 신호이며 스레드를 무작위로 차단 해제합니다. 스레드가 여전히 실행되지 않으면 다시 차단됩니다. 다른 스레드가 다시 신호를 호출하지 않으면 시스템이 교착 상태가됩니다.
3. 동기화 된 키워드
잠금 및 조건 인터페이스는 프로그래머에게 높은 수준의 잠금 제어를 제공하지만 대부분의 경우 이러한 제어가 필요하지 않으며 Java 언어에 포함 된 메커니즘을 사용할 수 있습니다. Java 버전 1.0에서 시작하여 Java의 모든 객체에는 내부 잠금 장치가 있습니다. 동기화 된 키워드로 메소드가 선언되면 객체의 잠금이 전체 메소드를 보호합니다. 즉,이 방법을 호출하려면 스레드가 내부 객체 잠금을 얻어야합니다.
다시 말해서,
public synchronized void method () {}동등합니다
public void method () {this.lock.lock (); try {} 마침내 {this.lock.unlock ();} 위의 은행 예에서는 은행 클래스의 전송 방법을 표시된 잠금 장치를 사용하는 대신 동기화 된 것으로 선언 할 수 있습니다.
내부 객체 잠금에 대한 관련 조건은 하나뿐입니다. 대기 확대가 대기 세트에 스레드에 추가됩니다. NotifyAll 또는 알림 메소드가 대기 스레드를 차단 해제합니다. 다시 말해서, 대기는 calling.await ()와 동일합니다.
위의 예제 전송 방법은 다음과 같이 작성할 수 있습니다.
공개 동기화 된 무효 전송 (int from, int to, int fumber)은 InterruptedException {while (when } // 전송 작업 ... notifyall (); }동기화 된 키워드를 사용하여 코드를 작성하는 것이 훨씬 간단하다는 것을 알 수 있습니다. 물론이 코드를 이해하려면 각 객체에 내부 잠금 장치가 있고 잠금 장치에 내부 조건이 있음을 이해해야합니다. 잠금은 동기화 된 메소드를 입력하려는 스레드를 관리하고 조건은 대기를 호출하는 스레드를 관리합니다.
4. 동기 차단 <br /> 위의 모든 Java 객체에는 잠금 장치가 있으며 스레드는 동기화 방법을 호출하여 잠금을 얻을 수 있으며 잠금을 얻는 또 다른 메커니즘이 있습니다. 스레드가 다음 형식의 차단에 들어가면 동기화 블록을 입력하여 다음과 같습니다.
동기화 (OBJ) {}그래서 그는 OBJ의 자물쇠를 얻었습니다. 은행 클래스를 살펴 보겠습니다
공개 클래스 은행 {private double [] 계정; 개인 객체 잠금 = new Object (); 공공 은행 (int n, double initialbance) {concments = new double [n]; for (int i = 0; i <ac }} public void arransfer (int from, int to, int ave) {synchronized (lock) {// 송전 ...}}}여기에서 잠금 객체 생성은 단순히 각 Java 객체에서 보유한 잠금 장치를 사용하는 데 사용됩니다. 때때로 개발자는 객체의 잠금 장치를 사용하여 클라이언트 잠금이라고하는 추가 원자 작업을 구현합니다. 예를 들어, 벡터 클래스, 그 방법은 동기입니다. 이제 은행 잔고가 벡터에 저장되었다고 가정합니다.
public void 송장 (vector <bouble> 계정, int from, int to, int fumber) {accounts.set (from, ac 계정. 세트 (to, accounts.get (to)+금액;}Vecror 클래스의 Get and Set 방법은 동기식이지만 이것은 우리에게 도움이되지 않았습니다. 첫 번째 호출이 완료되면 하나의 스레드가 전송 메소드에서 실행할 권리가 거부 될 가능성이 있으므로 다른 스레드는 동일한 스토리지 위치에 다른 값을 저장했을 수 있지만이 잠금 장치를 가로 채울 수 있습니다.
public void transfer (vector <double> 계정, int from, int to, int ems) {synchronized (accounts) {ac accounts.set (to, ac클라이언트 잠금 (동기 코드 블록)은 매우 취약하며 일반적으로 권장되지 않습니다. 일반적으로 차단 대기열과 같은 java.util.concurrent 패키지에 제공된 클래스를 사용하는 것이 가장 좋습니다. 동기화 방법이 프로그램에 적합한 경우 동기화 방법을 사용해보십시오. 작성된 코드 수를 줄이고 오류 가능성을 줄일 수 있습니다. 잠금/조건 구조에서 제공하는 고유 한 기능을 사용해야하는 경우 잠금/조건 만 사용하십시오.
위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.