왜 스레드 동기화
변수 또는 객체에 동시에 액세스 할 수있는 여러 스레드가 있으면이 스레드에 읽기 및 쓰기 작업이 있으면 변수 값 또는 객체 상태가 혼란을 일으켜 프로그램 예외가 발생합니다. 예를 들어, 은행 계좌가 동시에 두 개의 스레드로 운영되는 경우, 하나는 100 위안을 인출하고 다른 하나는 100 위안을 절약합니다. 계정에 원래 10 위안이 있다고 가정하면 인출 스레드와 저장 스레드가 동시에 발생하면 어떻게됩니까? 자금 인출이 성공하지 못한 경우 계정 잔고는 100입니다. 돈 인출이 성공하면 계정 잔액은 0입니다. 명확하게 설명하기가 어렵습니다. 따라서 다중 스레드 동기화는이 문제를 해결하는 것입니다.
1. 동기화되지 않은 경우 코드
bank.java 패키지 스레드 테스트;/** * @author ww */public count {private int count; // 보증금 공개 void addmoney (int money) {coun t += money; out .println (System.currentTimeMillis ()+"저장 :"+money); : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :); void lookmoney () {system.out. (); 스레드 tad (new runnable () { @ public void run () {// todo auto-recenated method stub while (true {stride.sleep (1000);} catch (InterpruptedException e) {// auto- 생성 된 캐치 e.printstacktrace (); 스레드 (new Runnable () {@override public void run () {// todo 자동 생성 메소드 스터브 (true) {bank.submoney (100); bank.lookmoney (); system.out.println ( "/n "); try {strook.sleep (1000);} catch (InterruptedException e) {// todo 자동 생성 캐치 블록 e.printstacktrace ();}}}}); tsub.start (); tad.start () }}
코드는 매우 간단합니다. 설명하지 않겠습니다. 나는 그들 중 일부를 가로 채고, 매우 지저분하고, 글을 이해할 수 없습니다.
불충분 한 잔액 계정 잔액 : 0
불충분 한 잔액 계정 잔액 : 100
1441790503354 예금 : 100
계정 잔액 : 100
1441790504354 예금 : 100
계정 잔액 : 100
1441790504354 테이크 아웃 : 100
계정 잔액 : 100
1441790505355 예금 : 100
계정 잔액 : 100
1441790505355 테이크 아웃 : 100
계정 잔액 : 100
2. 동기 코드를 사용하십시오
(1) 동기화 방법 :
동기화 된 키워드를 수정하는 방법이 있습니다. Java의 각 객체에는 내장 잠금 장치가 있으므로이 키워드로 메소드를 수정할 때 내장 잠금 장치는 전체 메소드를 보호합니다. 이 방법을 호출하기 전에 내장 잠금 장치를 얻어야합니다. 그렇지 않으면 차단 상태에 있습니다.
수정 된 Bank.java
실행중인 결과를 살펴 보겠습니다.
불충분 한 잔액 계정 잔액 : 0
불충분 한 잔액 계정 잔액 : 0
1441790837380SAVED : 100
계정 잔액 : 100
1441790838380 테이크 아웃 : 100
계정 잔액 : 0
1441790838380SAVED : 100
계정 잔액 : 100
1441790839381 제거 : 100
계정 잔액 : 0
나는 그것이 즉시 이해한다고 생각합니다.
참고 : 동기화 된 키워드는 정적 메소드가 호출되면 전체 클래스가 잠겨 있습니다.
(2) 코드 블록 동기화
즉, 동기화 된 키워드로 수정 된 명령문 블록이 있습니다. 이 키워드로 수정 된 명령문 블록은 동기화를 달성하기 위해 내장 잠금 장치로 자동 추가됩니다.
Bank.java 코드는 다음과 같습니다.
패키지 스레드 테스트;/** * @author ww * */public class 뱅크 {private int count = 0; // 계정 잔액 // 보증금 public void addmoney (int money) {this) {count += money; System.out.println (System.CurrentTimeMillis ()+"+Money); .println ( "불충분 한 균형")} money.out.println; {System.out.println ( "계정 잔액 :"+count)};
작업 결과는 다음과 같습니다.
불충분 한 잔액 계정 잔액 : 0
1441791806699SAVED : 100
계정 잔액 : 100
1441791806700 테이크 아웃 : 100
계정 잔액 : 0
1441791807699SAVED : 100
계정 잔액 : 100
효과는 방법과 유사합니다.
참고 : 동기화는 높은 헤드 작업이므로 동기화 된 컨텐츠를 최소화해야합니다. 일반적으로 전체 메소드를 동기화 할 필요가 없습니다. 동기화 된 코드 블록을 사용하여 키 코드를 동기화하십시오.
(3) 스레드 동기화를 달성하기 위해 특수 도메인 변수 (휘발성)를 사용하십시오.
A.Volatile 키워드는 도메인 변수에 액세스하기위한 잠금 장치 메커니즘을 제공합니다.
b. 휘발성 사용을 사용하여 도메인을 수정하는 것은 가상 시스템에 다른 스레드가 도메인을 업데이트 할 수 있음을 알려주는 것과 같습니다.
c. 따라서 필드를 사용할 때마다 레지스터의 값을 사용하는 대신 필드를 다시 계산해야합니다.
D. volatile은 원자 연산을 제공하지 않으며 최종 유형의 변수를 수정하는 데 사용될 수 없습니다.
Bank.java 코드는 다음과 같습니다.
패키지 스레드 테스트;/ ** * @Author WW * */ Public Class Bank {개인 휘발성 int count = 0; // 계정 잔액 절약 public void addMoney (int money) {count += money.out.println; (System.CurrentTimeMillis () + " + money) // 공개 무효 조사 (int money) {if (count -money <0) {System.out.println ("불충분 한 균형 "); } money.out.println ( + system.currenttimeMillis ()} query public void lookmoney () {System.out.prin tln ( "계정 균형 " + count);}}
작동 효과는 어떻습니까?
불충분 한 잔액 계정 잔액 : 0
불충분 한 잔액 계정 잔액 : 100
1441792010959SAVED : 100
계정 잔액 : 100
1441792011960 테이크 아웃 : 100
계정 잔액 : 0
1441792011961SAVED : 100
계정 잔액 : 100
다시 이해할 수없고 다시 지저분한가? 이게 왜? 휘발성이 원자 연산을 보장 할 수 없으므로 휘발성은 동기화 된 교체 할 수 없기 때문입니다. 또한 휘발성은 컴파일러를 구성하여 코드를 최적화하므로 사용할 수 있으면 적용되지 않습니다. 그 원리는 스레드가 휘발성에 의해 수정 된 변수에 액세스하려고 할 때마다 캐시가 아닌 메모리에서 읽히므로 각 스레드에서 액세스하는 변수 값이 동일하다는 것입니다. 이를 통해 동기화를 보장합니다.
(4) 재입국 잠금을 사용하여 스레드 동기화를 달성하십시오
동기화를 지원하기 위해 새로운 java.util.concurrent 패키지가 Javase5.0에 추가되었습니다. ReintrantLock 클래스는 잠금 인터페이스를 구현하는 재진입의 상호 배타적 잠금 장치입니다.
ReenreanTlock 클래스의 일반적인 방법은 다음과 같습니다.
ReintrantLock () : ReintrantLock 인스턴스를 만듭니다
잠금 () : 잠금을 얻습니다
잠금 해제 () : ReintrantLock 참고 : ReintrantLock ()에는 공정한 잠금 장치를 만들 수있는 생성자가 있지만 프로그램의 실행 효율성을 크게 줄일 수 있기 때문에 사용하지 않는 것이 좋습니다.
Bank.java 코드는 다음과 같이 수정됩니다.
패키지 스레드 테스트; import java.util.concurrent.locks.lock; java.util.concurrent.locks.reentrantlock; //이 잠금 잠금 잠금 장치를 선언해야합니다 tln (system .currenttimeMillis () + " + money); if (count -money <0) {system.out.println ( "불충분 한 균형"); } 마침내 {lock.unlock ()};
작동 효과는 어떻습니까?
불충분 한 잔액 계정 잔액 : 0
불충분 한 잔액 계정 잔액 : 0
1441792891934 예금 : 100
계정 잔액 : 100
1441792892935SAVED : 100
계정 잔액 : 200
1441792892954 테이크 아웃 : 100
계정 잔액 : 100
효과는 처음 두 가지 방법과 유사합니다.
동기화 된 키워드가 사용자의 요구를 충족 할 수있는 경우 코드를 단순화 할 수 있으므로 동기화 된 사용을 사용하십시오. 더 많은 고급 기능이 필요한 경우,이 시점에서 잠금을 해제하십시오. 그렇지 않으면 교착 상태가 나타납니다.
(5) 로컬 변수를 사용하여 스레드 동기화를 달성합니다
Bank.java 코드는 다음과 같습니다.
패키지 스레드 테스트; / ** * @author ww * * / public class bank {private static stroodlocal <integer> count = new ThreadLocal <integer> () {@override p 회전 된 Integer InitialValue () {// TODO 자동 생성 메소드 스튜어트 return 0;}; ); ()- money); system.out.println ( + system.currenttimeMillis () + " + money) // 쿼리 public void lookmoney () {System.out.println ("계정 잔액 : " +. get ());}}.
실행 효과 :
불충분 한 잔액 계정 잔액 : 0
불충분 한 잔액 계정 잔액 : 0
1441794247939SAVED : 100
계정 잔액 : 100
불충분 한 균형
1441794248940SAVE : 100
계정 잔액 : 0
계정 잔액 : 200
불충분 한 잔액 계정 잔액 : 0
1441794249941SAVED : 100
계정 잔액 : 300
작동 효과를 본 후, 나는 왜 저장을 허용하고 철수하지 않았습니까? ThreadLocal의 원리를 살펴보십시오.
ResdleLocal을 사용하여 변수를 관리하는 경우 변수를 사용하는 각 스레드는 변수의 사본을 얻고 사본은 서로 독립적이므로 각 스레드는 다른 스레드에 영향을 미치지 않고 자체 변수의 사본을 수정할 수 있습니다. 이제 이해합니다. 각 스레드가 사본을 실행한다는 것을 이해합니다. 이는 돈을 절약하고 돈을 인출하는 것이 동일한 지식 이름을 가진 두 계정임을 의미합니다. 위의 효과가 발생합니다.
ThreadLocal 및 동기화 메커니즘
A. Threadlocal 및 Synchronization 메커니즘은 모두 멀티 스레드에서 동일한 변수의 액세스 충돌 문제를 해결하기위한 것입니다.
b.
이제 이해합니다. 각각 고유 한 장점과 단점이 있으며이 기사가 Java Multithreading Synchronization에 대한 더 깊은 이해를 얻을 수 있기를 바랍니다.