[java] '동기화'란 무엇입니까?


Answers

이론적 인 설명이 충분하다고 생각합니다. 따라서이 코드를 고려하십시오.

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

참고 : synchronized 는 이전 스레드의 실행이 완료되지 않는 한 test () 메서드에 대한 다음 스레드의 호출을 차단합니다. 스레드는이 메소드를 한 번에 하나씩 액세스 할 수 있습니다. synchronized 없는 경우, 모든 thread가이 메소드에 동시에 액세스 할 수 있습니다.

쓰레드가 'TheDemo'클래스의 인스턴스 인 객체의 동기화 된 메소드 'test'를 호출하면 그 객체의 잠금을 획득하며, 새로운 쓰레드는 이전 쓰레드와 동일한 객체의 동기화 된 메소드를 호출 할 수 없다. 자물쇠를 획득 한자는 자물쇠를 해제하지 않습니다.

클래스의 정적 동기화 된 메서드가 호출 될 때도 비슷한 결과가 발생합니다. 스레드는 클래스와 연관된 잠금을 획득합니다 (이 경우 객체 레벨 잠금이 여전히 사용 가능하기 때문에이 클래스의 인스턴스에 대해 정적이 아닌 동기화 된 메소드는 모든 스레드가 호출 할 수 있습니다). 다른 스레드는 현재 클래스 잠금이 현재 잠금을 보유하고있는 스레드에 의해 해제되지 않는 한 클래스의 정적 동기화 된 메서드를 호출 할 수 없습니다.

동기화 된 출력

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

동기화되지 않은 출력

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9
Question

synchronized 키워드의 사용법과 중요성에 대해 몇 가지 질문이 있습니다.

  • synchronized 키워드의 의미는 무엇입니까?
  • 메소드는 언제 synchronized 되어야합니까?
  • 프로그래밍 적으로나 논리적으로 무엇을 의미합니까?



Synchronized normal method Synchronized statement 동등한 Synchronized normal method (사용)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static method Synchronized statement 동등한 Synchronized static method (클래스 사용)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

동기화 된 문 (변수 사용)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

synchronized 경우 Synchronized MethodsSynchronized Statements 이 모두 있습니다. 그러나 Synchronized MethodsSynchronized Statements 와 유사하므로 Synchronized Statements 를 이해하면됩니다.

=> 기본적으로, 우리는

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

여기에 2는 synchronized 이해를 돕는 것이라고 생각합니다.

  • 모든 객체 / 클래스에는 intrinsic lock 이 있습니다.
  • 스레드가 synchronized statement 호출하면 자동으로 해당 synchronized statement's 개체에 대한 intrinsic lock 을 가져 와서 메서드가 반환 될 때 해제합니다. 스레드가 intrinsic lock 소유하고있는 한, 다른 스레드는 SAME 잠금 => 스레드 안전을 획득 할 수 없습니다 .

=> thread Asynchronized(this){// code 1} => 모든 블록 코드 (내부 클래스)를 호출하면 SAME 잠금으로 인해 모든 synchronized normal method (내부 클래스)가 잠겨집니다. thread A 잠금 해제 ( "// 코드 1"완료) 후에 실행됩니다.

이 동작은 synchronized(a variable){// code 1} 또는 synchronized(class) 와 유사합니다.

SAME LOCK => lock (어떤 메소드 또는 어떤 문장에 의존하지 않는가?)

동기화 된 메서드 또는 동기화 된 문 사용?

나는 그것이 더 확장 가능하기 때문에 synchronized statements 선호한다. 예를 들어, 나중에 메소드의 일부만 동기화하면됩니다. 예를 들어 동기화 된 메서드가 2 개 있고 서로 관련성이 없지만 스레드가 메서드를 실행할 때 다른 메서드를 차단합니다 ( synchronized(a variable) 사용)을 방지 할 수 synchronized(a variable) ).

그러나 동기화 된 메소드를 적용하는 것은 간단하고 코드는 단순 해 보입니다. 어떤 클래스의 경우, 오직 하나의 동기화 된 메소드, 또는 서로 관련된 클래스의 모든 동기화 된 메소드 => synchronized method 를 사용하여 코드를 더 짧고 이해하기 쉽게 만들 수 있습니다

노트

( synchronized 와 관련이 없으며, 객체와 클래스 또는 정적이 아니고 정적 인 것의 차이입니다.)

  • synchronized 또는 normal 메소드 또는 synchronized(this) 또는 synchronized(non-static variable) 하면 각 객체 인스턴스의 기반을 동기화합니다.
  • synchronized 또는 정적 메서드 또는 synchronized(class) 또는 synchronized(static variable) 하면 클래스 기반을 동기화합니다.

참고

effects page

희망이 도움이




synchronized 키워드 란 무엇입니까?

쓰레드는 주로 필드에 대한 액세스를 공유함으로써 통신하며 객체 참조 필드는 참조합니다. 이러한 형태의 통신은 매우 효율적이지만 스레드 간섭과 메모리 일관성 오류 라는 두 가지 종류의 오류가 발생합니다. 이러한 오류를 방지하는 데 필요한 도구는 동기화입니다.

동기화 된 블록 또는 메소드는 스레드 간섭을 방지하고 데이터가 일관성이 있는지 확인합니다. 언제든지 하나의 스레드 만 잠금을 획득하여 동기화 된 블록 또는 메소드 ( 중요 섹션 )에 액세스 할 수 있습니다. 다른 스레드는 임계 영역 에 액세스하기 위해 잠금 해제를 기다립니다.

방법은 언제 동기화됩니까?

메서드 정의 또는 선언에 synchronized 를 추가하면 메서드가 동기화됩니다. 특정 코드 블록을 메소드에서 동기화 할 수도 있습니다.

문법적으로나 논리적으로 프로라는 것이 무엇을 의미합니까?

이는 하나의 스레드 만 잠금을 획득하여 중요 섹션 에 액세스 할 수 있음을 의미합니다. 이 스레드가이 잠금을 해제하지 않으면 다른 모든 스레드가 잠금을 획득하기 위해 대기해야합니다. 그들은 자물쇠를 구입하지 않고도 중요한 섹션 에 들어갈 수있는 권한이 없습니다.

이것은 마법으로 할 수 없습니다. 응용 프로그램에서 중요한 섹션 을 식별하고 적절하게 보호하는 것은 프로그래머의 책임입니다. Java는 응용 프로그램을 보호하기위한 프레임 워크를 제공하지만 보호해야 할 모든 섹션이 프로그래머의 책임입니다.

java 문서 page 에서 자세한 내용보기

본질적인 잠금 및 동기화 :

동기화는 내장 잠금 또는 모니터 잠금이라고하는 내부 엔티티를 기반으로합니다. Intrinsic 잠금은 객체 상태에 대한 독점적 액세스를 수행하고 가시성에 필수적인 선행 관계를 설정하는 등의 두 가지 측면에서 동기화의 역할을합니다.

모든 객체에는 고유 한 잠금이 있습니다 . 관습 적으로, 객체의 필드에 배타적이고 일관된 액세스가 필요한 스레드는 객체의 고유 한 잠금을 액세스하기 전에 가져와야하며, 잠금이 끝나면 내장 잠금을 해제해야합니다.

스레드는 잠금을 획득하고 잠금을 해제 한 시간 사이에 고유 잠금을 소유한다고합니다. 스레드가 고유 잠금을 소유하고있는 한 다른 스레드는 동일한 잠금을 획득 할 수 없습니다. 다른 스레드는 잠금 획득을 시도 할 때 차단됩니다.

스레드가 고유 잠금을 해제하면 해당 동작과 이후에 동일한 잠금을 획득 할 때 발생 - 관계가 설정됩니다.

동기화 된 메소드를 만드는 것은 두 가지 effects .

우선, 같은 오브젝트상의 동기 메소드의 2 회의 호출은 인터리브 할 수 없습니다.

한 스레드가 객체에 대해 동기화 된 메소드를 실행할 때 첫 번째 스레드가 객체로 완료 될 때까지 동일한 객체 블록 (실행 중단)에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드.

둘째, 동기화 된 메소드가 종료되면 동일한 객체에 대한 동기화 된 메소드의 후속 호출과 자동으로 '발생 - 이전'관계를 설정합니다.

이렇게하면 모든 스레드에서 객체 상태에 대한 변경 사항을 볼 수 있습니다.

동기화의 다른 대안을 찾으십시오.

Java에서 동기화되지 않습니까?




synchronized 는 다중 스레드 환경에서 synchronized 메소드 / 블록이있는 객체가 두 스레드가 동시에 synchronized 메소드 / 블록 (들)에 액세스하지 못하게 함을 의미합니다. 이는 다른 스레드가 스레드를 업데이트하는 동안 한 스레드가 읽을 수 없음을 의미합니다.

두 번째 스레드는 첫 번째 스레드가 실행을 완료 할 때까지 대기합니다. 오버 헤드는 속도이지만 장점은 데이터의 일관성을 보장한다는 것입니다.

응용 프로그램이 단일 스레드인데도 synchronized 블록은 이점을 제공하지 않습니다.




개요

Java의 동기화 된 키워드는 스레드 안전성과 관련이 있습니다. 즉, 여러 스레드가 동일한 변수를 읽거나 쓰는 경우입니다.
이는 직접 (동일한 변수에 액세스하여) 또는 간접적으로 (동일한 변수에 액세스하는 다른 클래스를 사용하는 클래스를 사용하여) 발생할 수 있습니다.

synchronized 키워드는 여러 스레드가 동일한 변수에 안전하게 액세스 할 수있는 코드 블록을 정의하는 데 사용됩니다.

더 깊게

Syntax-wise는 synchronized 키워드가 Object 를 매개 변수 ( 잠금 객체 라고 함)로 취한 다음 { block of code } .

  • 실행시이 키워드가 발생하면 현재 스레드가 잠금 객체 를 "lock / acquire / own"(선택)하고 잠금을 획득 한 후 연관된 코드 블록을 실행하려고합니다.

  • 동기화 된 코드 블록 내부의 변수에 대한 모든 쓰기는 동일한 잠금 객체를 사용하여 동기화 된 코드 블록 내에서 코드를 유사하게 실행하는 다른 모든 스레드에서 볼 수 있습니다.

  • 한 번에 하나의 스레드 만 잠금을 유지할 수 있으며, 그 동안 동일한 잠금 객체 를 얻으려는 다른 모든 스레드는 대기합니다 (실행을 일시 중지합니다). 실행이 동기화 된 코드 블록을 종료하면 잠금이 해제됩니다.

동기화 된 메소드 :

synchronized 키워드를 메소드 정의에 추가하는 것은 잠금 객체this (예 : 메소드) 이고 ClassInQuestion.getClass() (클래스 메소드) 인 동기화 된 코드 블록에 래핑되는 전체 메소드 본문과 ClassInQuestion.getClass() .

- 인스턴스 메소드는 static 키워드가없는 메소드입니다.
- 클래스 메소드는 static 키워드를 가지는 메소드입니다.

전문인

동기화가 없으면 읽기 및 쓰기 순서가 보장되지 않으므로 변수에 가비지가 남을 수 있습니다.
(예를 들어 변수는 하나의 쓰레드에 의해 쓰여진 비트의 절반과 다른 쓰레드에 의해 쓰여진 비트의 절반으로 끝날 수 있습니다. 쓰레드가 쓰려고 시도하지 않은 상태에서 변수를 남겨 두지 만 둘 모두를 혼란으로 만듭니다.)

하드웨어가 변수의 값을 캐싱 할 수 있고 쓰레드가 쓰여진 값 대신 캐싱 된 값을 볼 수 있기 때문에 다른 쓰레드가 그것을 읽는 (wall-clock time) 전에 쓰기 작업을 완료하는 것만으로는 충분하지 않습니다 그것.

결론

따라서 Java의 경우 스레딩 오류가 발생하지 않도록 Java 메모리 모델을 따라야합니다.
다른 말로하면 : 동기화, 원자 적 연산 또는 클래스를 사용합니다.

출처

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Java® 언어 사양, 2015-02-13




다른 답변이 누락 된 부분 중 하나는 중요한 장벽 인 메모리 장벽 입니다. 스레드 동기화는 기본적으로 직렬화와 가시성의 부분으로 구성됩니다. 저는 "jvm memory barrier"에 대해 모든 사람들에게 google에 조언합니다. 이는 중요하지 않은 중요한 주제이기 때문에 (여러 스레드가 액세스하는 공유 데이터를 수정하는 경우). 이 작업을 수행 한 후에 명시 적 동기화 사용을 피하는 데 도움이되는 java.util.concurrent 패키지의 클래스를 살펴보고 프로그램을 간단하고 효율적으로 유지하는 데 도움이되며 교착 상태를 방지 할 수도 있습니다.

그러한 예가 ConcurrentLinkedDeque 입니다. 커맨드 패턴 과 함께 커맨드 패턴 을 동시 대기열에 채워서 매우 효율적인 작업자 스레드를 만들 수 있습니다. 명시 적 동기화가 필요없고 교착 상태가 발생하지 않으며 명시 적 sleep ()이 필요하지 않으며 take ()를 호출하여 대기열을 폴링하면됩니다.

간단히 말해, "메모리 동기화"는 암시 적으로 발생합니다. 스레드를 시작하면 스레드가 종료되고 휘발성 변수를 읽은 다음 모니터를 잠금 해제합니다 (동기화 된 블록 / 함수를 남겨 두는 등). "동기화"는 영향을줍니다 ( "플러시 ") 모든 특정 작업 전에 완료된 쓰기. 앞서 언급 한 ConcurrentLinkedDeque 의 경우 문서 "says":

메모리 일관성 효과 : 다른 동시 수집과 마찬가지로 ConcurrentLinkedDeque에 객체를 배치하기 전에 스레드의 작업 happen-before 합니다. 다른 스레드의 ConcurrentLinkedDeque에서 해당 요소에 액세스하거나 해당 요소를 제거한 후에 수행됩니다.

이 암시적인 동작은 다소 위험한 측면입니다. 많은 경험이없는 대부분의 자바 프로그래머는 주어진 이유로 많이 사용하게 될 것이기 때문입니다. 그리고 나서 Java가 다른 작업 부하가있는 "프로덕션"에서 수행 할 작업을 수행하지 않은 후에 갑자기이 스레드 위로 넘어져서 동시성 문제를 테스트하기가 꽤 어렵습니다.




나는 당신이 이미 당신의 답을 알고 있음을 압니다.
나는이 글을 쓰면서, 같은 질문을 가진 사람들을 돕기 위해이 페이지를 훑어보고있다.
여기에 effects 대한 설명이있다.

다음 코드를 살펴보십시오.

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

countSynchronizedCounter 의 인스턴스 인 경우 이러한 메서드를 동기화하면 두 가지 효과가 있습니다.

  • 우선, 같은 오브젝트상의 동기 메소드의 2 회의 호출은 인터리브 할 수 없습니다. 한 스레드가 객체에 대해 동기화 된 메소드를 실행할 때 첫 번째 스레드가 객체로 완료 될 때까지 동일한 객체 블록 (실행 중단)에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드.
  • 둘째, 동기화 된 메소드가 종료되면 동일한 객체에 대한 동기화 된 메소드의 후속 호출과 자동으로 '발생 - 이전'관계를 설정합니다. 이렇게하면 모든 스레드에서 객체 상태에 대한 변경 사항을 볼 수 있습니다.



Links