Java 기초 학습의 스레드 동기화 방법 총결

루틴 동기화를 도입하는 원인: 여러 개의 루틴이 변수나 대상에 동시에 접근해야 할 때 이 루틴에 읽기와 쓰기가 있을 때 변수 값이나 대상의 상태가 혼란스러워져 프로그램 이상을 초래하고 사용자도 원하는 결과를 얻지 못한다.예를 들어 만약에 한 은행 계좌가 두 라인에 동시에 조작된다면 하나는 100위안을 찾고, 하나는 100위안을 저축한다.계좌에 원래 0위안이 있었다고 가정하면 인출 라인과 예금 라인이 동시에 발생하면 어떤 결과가 나올까요?돈을 인출하는 데 성공하지 못하면 계좌 잔액이 100이다.인출에 성공했습니다. 계좌 잔액은 0입니다.그게 도대체 뭘까요?분명히 말하기 어렵다.다중 스레드가 동기화되면 이 문제를 쉽게 해결할 수 있다.멀티스레드 동기화에는 주로 다음과 같은 몇 가지 방법이 있습니다.

1. 동기화 방법


동기화 방법은 synchronized 키워드로 수식하는 방법입니다. java의 모든 대상에 내장 자물쇠가 있기 때문에 이 키워드로 수식할 때 내장 자물쇠는 전체 방법을 보호합니다.이 방법을 사용하기 전에 내장 자물쇠를 가져와야 한다. 그렇지 않으면 막힌 상태에 있다.코드는 다음과 같습니다.
public synchronized void save(){}

  PS:synchronized 키워드도 정적 메소드를 수정할 수 있습니다. 이 정적 메소드를 사용하면 클래스 전체가 잠깁니다.  synchronized는 가시성을 확보할 수 있을 뿐만 아니라 원자성을 확보할 수 있다.  (1), 가시성은 다음과 같다. synchronized나 Lock을 통해 같은 시간에 한 라인만 자물쇠를 가져오고 동기화 코드를 실행할 수 있으며 자물쇠를 풀기 전에 변수에 대한 수정을 메인 메모리로 갱신할 수 있다. (2), 원자성은 집행하지 않거나 끝까지 집행하는 데 나타난다.

2. 코드 블록 동기화


동기화 코드 블록은synchronized 키워드로 장식된 문장 블록입니다.이 키워드로 장식된 문장 블록은 자동으로 내장 자물쇠가 추가되어 동기화됩니다.코드는 다음과 같은 단일 예제 모드에서 잠금 방식을 이중으로 검사하는 실례적인 방법입니다.
    // 
    public static SingleTon getInstance(){
        if (singleTonInstance==null){
            synchronized (SingleTon.class){
                if (singleTonInstance==null){
                    singleTonInstance = new SingleTon();
                }
            }
        }
        return singleTonInstance;
    }


  PS: 동기화는 비용이 많이 드는 작업이므로 동기화 내용을 최소화해야 합니다.일반적으로 전체 방법을 동기화할 필요가 없습니다.synchronized 코드 블록을 사용하여 관건적인 코드를 동기화하면 됩니다.

3. 특수역 변수(volatile)를 사용하여 라인 동기화


 volatile 수식역을 사용하는 것은 가상 머신에 이 영역이 다른 라인으로 업데이트될 수 있음을 알려주는 것과 같습니다. 따라서 이 영역을 사용할 때마다 레지스터의 값을 사용하지 않고 메모리에서 가져와야 합니다.volatile는 어떠한 원자 조작도 제공하지 않으며,final 형식의 변수를 수식하는 데도 사용할 수 없습니다. volatile은 변수 수식자로서 수식의 변수는 가시성을 가진다.가시성 즉, 어떤 라인이volatile에 의해 수식된 변수를 수정하면 수정된 값이 메모리로 즉시 업데이트되고, 다른 라인이 읽을 필요가 있을 때 수정된 값을 즉시 얻을 수 있다는 것이다.자바에서 프로그램의 운행 효율을 높이기 위해 일부 변수에 대한 조작은 보통 이 라인의 레지스터나 CPU 캐시에서 이루어지고 그 후에야 메인 메모리에 동기화되며volatile 수식자를 추가한 변수는 메인 메모리를 직접 읽고 쓰는 것이다.  PS: 다중 스레드의 비동기화 문제는 주로 도메인에 대한 읽기와 쓰기에 나타나므로 도메인 자체에서 이 문제를 방지하려면 도메인을 조작하는 방법을 수정할 필요가 없습니다.final역으로 잠금 보호된 역과volatile역은 비동기적인 문제를 피할 수 있습니다.

4. 리셋 자물쇠를 사용하여 라인 동기화


  ReentrantLock 클래스는 Lock 인터페이스를 재입출력, 배척, 구현하는 잠금으로 synchronized 메소드를 사용하거나 동일한 기본 동작과 의미를 가지며 능력을 확장하는 ReenreantLock 클래스의 일반적인 방법은 다음과 같습니다.
ReentrantLock(): ReentrantLock 
lock() :   
unlock() :  

  PS: Lock 객체와 synchronized 키워드에 대한 선택:   a. synchronized 키워드가 사용자의 요구를 충족시킬 수 있다면 synchronized를 사용합니다. 코드를 간소화할 수 있기 때문입니다.  b. 더 높은 기능이 필요하면 ReentrantLock 클래스를 사용합니다. 이 때 자물쇠를 제때에 풀어야 합니다. 그렇지 않으면 사라진 자물쇠가 나타납니다. 보통finally 코드에서 자물쇠를 풀어줍니다.

5. 국부 변수를 사용하여 라인 동기화


 ThreadLocal을 사용하여 변수를 관리할 때 이 변수를 사용하는 모든 루트는 이 변수의 복사본을 얻고 복사본 간에 서로 독립된다. 이렇게 하면 모든 루트는 자신의 변수 복사본을 마음대로 수정할 수 있으며 다른 루트에 영향을 주지 않는다.  PS: ThreadLocal과 동기화 메커니즘은 모두 다중 스레드에서 같은 변수의 접근 충돌 문제를 해결하기 위해 전자는'공간으로 시간을 바꾸는'방법을 사용하고 후자는'시간으로 공간을 바꾸는'방식을 사용한다.

6. 차단 대기열을 사용하여 라인 동기화


  Linked BlockingQueue는 연결된 노드를 기반으로 하는 범위가 임의의 Blocking queue입니다.대기열은 먼저 나가는 순서(FIFO)

7. 원자 변수를 사용하여 라인 동기화


  가 라인 동기화를 사용해야 하는 근본적인 원인은 일반 변수에 대한 조작이 원자가 아니기 때문이다.  원자 조작은 변수 값을 읽거나 수정하거나 변수 값을 하나의 전체로 저장하는 것을 말한다. 즉, 이 몇 가지 행위가 동시에 완성되거나 완성되지 않는 것을 말한다.

좋은 웹페이지 즐겨찾기