자바 동시성 (03) : 다중 스레드 동시 액세스, 동기화 제어

이 문서 출처 : GitHub의이 · 여기를 클릭 || GitEE이 · 여기를 클릭하십시오

첫째, 동시성 문제

당신이 원하는 변수 값을 스레딩 후되지 않습니다 멀티 스레드 학습, 복잡한 문제에 직면하는 첫번째는 분명 내부 프로세스 및 이유를 무시할 경우 그 액세스 동시 모드 변수, 종종 문제가있을 것입니다 또한 말할 필요도 무지 보일 수 있습니다 :이 비논리적 맞아?

1 멤버 변수 접근

액세스 클래스 멤버 변수에 대한 다중 스레드, 다양한 문제가 발생할 수 있습니다.

public class AccessVar01 {
    public static void main(String[] args) {
        Var01Test var01Test = new Var01Test() ;
        VarThread01A varThread01A = new VarThread01A(var01Test) ;
        varThread01A.start();
        VarThread01B varThread01B = new VarThread01B(var01Test) ;
        varThread01B.start();
    }
}
class VarThread01A extends Thread {
    Var01Test var01Test = new Var01Test() ;
    public VarThread01A (Var01Test var01Test){
        this.var01Test = var01Test ;
    }
    @Override
    public void run() {
        var01Test.addNum(50);
    }
}
class VarThread01B extends Thread {
    Var01Test var01Test = new Var01Test() ;
    public VarThread01B (Var01Test var01Test){
        this.var01Test = var01Test ;
    }
    @Override
    public void run() {
        var01Test.addNum(10);
    }
}
class Var01Test {
    private Integer num = 0 ;
    public void addNum (Integer var){
        try {
            if (var == 50){
                num = num + 50 ;
                Thread.sleep(3000);
            } else {
                num = num + var ;
            }
            System.out.println("var="+var+";num="+num);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

흐름은 멤버 변수 동시 동작되는 경우는, 프로그램이 의도된다 수득 VAR NUM = 50 = 50, 실제 출력 결과는 :

var=10;num=60
var=50;num=60

VarThread01A 스레드 처리가 절전 모드로 전환, NUM은 VarThread01B 나사산 의한 멀티 스레드 동시 액세스의 결과 인 수면 시간 + 10 동작을 실시하고있다.

2. 전용 변수의 방법

로직 전용 가변하는 방법으로서, 변수의 num 방법에 넣고 위의 코드를 수정한다.

class Var01Test {
    // private Integer num = 0 ;
    public void addNum (Integer var){
        Integer num = 0 ;
        try {
            if (var == 50){
                num = num + 50 ;
                Thread.sleep(3000);
            } else {
                num = num + var ;
            }
            System.out.println("var="+var+";num="+num);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

내부 방법 변수는 전용이며, 하나의 현재 스레드의 실행에있어서, 스레드 간의 간섭이 없음.

둘째, 동기 제어

1, 동기화 키워드

용도 : 또는 동시에 다수의 스레드를 보장 싱크 블록의 제어 형태의 변형 방법, 프로세스, 또는 동기 부호 블록에 한 번에 하나 개의 스레드 만하므로 그 스레드 안전 액세스 프로세스 변수. 수정이 정적 메서드 인 경우, 모두의 역할은이 클래스의 객체.

독점 잠금 동기화, 비관적 잠금의 클래스에 속하는 최악의 경우, 다른 스레드를 차단, 실행 한 스레드가 있다고 가정하고, 배타적 잠금의 종류, 높은 동시성, 시간이 많이 소요되는 프로세스가 여러 개의 스레드로 이어질 것입니다 경우 보류 기다리고 교수형, 잠금 스레드가 잠금을 해제합니다.

제 2 변형 수단

이 경우 첫 번째 경우 원칙은 동일하지만, 여기에 수정 된 값은 동기화 제어를 추가하지만 대신에, 그러나 그들은 구덩이를 파고, 열람하는 시점까지의 기간에 제한이 없습니다, 일반적으로 더러운 읽기로 알려진 현상.

public class AccessVar02 {
    public static void main(String[] args) {
        Var02Test var02Test = new Var02Test ();
        VarThread02A varThread02A = new VarThread02A(var02Test) ;
        varThread02A.start();
        VarThread02B varThread02B = new VarThread02B(var02Test) ;
        varThread02B.start();
        var02Test.readValue();
    }
}
class VarThread02A extends Thread {
    Var02Test var02Test = new Var02Test ();
    public VarThread02A (Var02Test var02Test){
        this.var02Test = var02Test ;
    }
    @Override
    public void run() {
        var02Test.change("my","name");
    }
}
class VarThread02B extends Thread {
    Var02Test var02Test = new Var02Test ();
    public VarThread02B (Var02Test var02Test){
        this.var02Test = var02Test ;
    }
    @Override
    public void run() {
        var02Test.change("you","age");
    }
}
class Var02Test {
    public String key = "cicada" ;
    public String value = "smile" ;
    public synchronized void change (String key,String value){
        try {
            this.key = key ;
            Thread.sleep(2000);
            this.value = value ;
            System.out.println("key="+key+";value="+value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void readValue (){
        System.out.println("读取:key="+key+";value="+value);
    }
}

스레드에서 논리가 수정되었습니다,하지만 수행하지 않도록하지만, 값은 의미가 아니라 읽기 방법에 대한 스레드 동기화 제어에 가입해야 메인 스레드에서 읽어 보시기 바랍니다.

(3), 동기 제어 로직

객체 구현은 동기화 제어 모니터를 기반으로합니다.

  • 개체에 대한 스레드 액세스 개체 먼저 모니터를 얻을;
  • 인수에 성공하면, 대상은 독점 될 것입니다;
  • 다른 스레드 동기화 큐에 속하는 것, 스레드 상태가 차단된다;
  • 개체 소유자 및 다른 스레드 해제 잠금, 대기열에서 대기 깨어나 실, 획득 객체 모니터를 다시 시작합니다;

(4) 변형 된 코드 블록

지적 논리 코드 블록은 모든 방법을 포함 록킹 절차의 입경 및 변형 방법에 쓰기 동일하다. 동기화 블록은 크기 감소는 테이블 잠금 및 행 수준 잠금 장치로, 자원을 고정, 핵심 목적이다.

public class AccessVar03 {
    public static void main(String[] args) {
        Var03Test var03Test1 = new Var03Test() ;
        Thread thread1 = new Thread(var03Test1) ;
        thread1.start();
        Thread thread2 = new Thread(var03Test1) ;
        thread2.start();
        Thread thread3 = new Thread(var03Test1) ;
        thread3.start();
    }
}
class Var03Test implements Runnable {
    private Integer count = 0 ;
    public void countAdd() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized(this) {
            count++ ;
            System.out.println("count="+count);
        }
    }
    @Override
    public void run() {
        countAdd() ;
    }
}

다음은 동시 처리를 허용하지 않는, 동작의 잠금 횟수 프로세싱 코어 로직에 대한 코드이다.

(5) 변형 정적 메소드

방법 정적 메소드는 클래스 계층에 속하는 객체를 직접 호출하지 않습니다. 그러나 정적 방법 잠금 장치의 동기화 변경은 모두이 클래스의 객체이다.

public class AccessVar04 {
    public static void main(String[] args) {
        Var04Test var04Test1 = new Var04Test() ;
        Thread thread1 = new Thread(var04Test1) ;
        thread1.start();
        Var04Test var04Test2 = new Var04Test() ;
        Thread thread2 = new Thread(var04Test2) ;
        thread2.start();
    }
}
class Var04Test implements Runnable {
    private static Integer count ;
    public Var04Test (){
        count = 0 ;
    }
    public synchronized static void countAdd() {
        System.out.println(Thread.currentThread().getName()+";count="+(count++));
    }
    @Override
    public void run() {
        countAdd() ;
    }
}

동기 제어를 사용하여, 논리적 감각 출력되지 않은 경우 다음과 같은 결과가 같아야

Thread-0;count=0
Thread-1;count=0

동기 제어 실제 테스트 출력을 첨가 한 후 :

Thread-0;count=0
Thread-1;count=1

6 주

  • 상속 중성자 부모 클래스는 명시 적으로 선언해야하는 방법, 동기화 된 전송 키가 아닌 상속 특성을 무시;
  • 동기화 키워드 공법, 생성자 동기 블록 지원에 사용될 수 없다;
  • 방법 인터페이스, 추상적 인 방법은 동기화 된 키워드를 지원하지 않습니다;

세, 휘발성 키워드

1 기본 설

자바 메모리 모델은 성능을 향상시키기 위해, 변수의 스레드 사본은 자신의 작업 메모리에 방문합니다. 따라서 한번에 같은 변수가되며, 나사 환경에서의 값은 다른 스레드 환경의 값에 관련 될 수 있으며, 일관성 나타난다.

모든 스레드의 변수의 가시성을 보장하기 위해 공유 메모리에 플러시이 변수를 액세스 할 때 스레드가 공유 메모리에서 얻을 필요가있는 식별이 변수가 수정뿐만 아니라 동기화해야한다, 방법은 수정할 수 없습니다, 휘발성 수정 멤버 변수를 사용 .

2, 사용 사례

class Var05Test {
    private volatile boolean myFlag = true ;
    public void setFlag (boolean myFlag){
        this.myFlag = myFlag ;
    }
    public void method() {
        while (myFlag){
            try {
                System.out.println(Thread.currentThread().getName()+myFlag);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3 주

  • 가시성은 각 최신 값을 읽을 수 있도록하지만, 원자 변수 작업을 지원하지 않습니다;
  • 휘발성 및 쓰레드 방식을 차단하지 않고, 동기 제어를 차단하는 것;
  • 기본적인 자바 동기화 제어 : 열등 자원 자성 및 가시성을 보장하기 위해;

넷째, 소스 주소

GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent

자바 동시성 (03) : 다중 스레드 동시 액세스, 동기화 제어

추천

출처blog.51cto.com/14439672/2482929