'동기화'란 무엇입니까?


993

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

  • synchronized키워드 의 의미는 무엇입니까 ?
  • 방법은 언제해야 synchronized합니까?
  • 프로그래밍 방식 및 논리적 의미는 무엇입니까?


1
해시 맵과 해시 테이블 간의 유용한 토론 및 동기화 : stackoverflow.com/questions/40471/java-hashmap-vs-hashtable
limc


1
첫 번째 주석에서 전체 문서 링크를 살펴 보았고 마지막 단락에 도달 할 때까지 이해하지 못했습니다. 링크를 붙여넣고 인용하는 대신 링크를 붙여넣고 따옴표를 추가하는 것이 더 도움이됩니다.
Rakib

답변:


878

synchronized키워드는 읽기와 같은 변수, 객체, 자원에 쓰는 다른 스레드에 대한 모든 것입니다. 이것은 Java에서 사소한 주제는 아니지만 Sun의 인용문입니다.

synchronized 메소드는 스레드 간섭 및 메모리 일관성 오류를 방지하기위한 간단한 전략을 가능하게합니다. 오브젝트가 둘 이상의 스레드에 표시되면 해당 오브젝트 변수에 대한 모든 읽기 또는 쓰기는 동기화 된 메소드를 통해 수행됩니다.

매우 작은 요컨대 , 같은 '자원'에 읽고 쓰는 두 개의 스레드가있는 경우 (예 : 변수) foo, 이러한 스레드가 원자 방식으로 변수에 액세스해야합니다. synchronized키워드가 없으면 스레드 1이 변경 스레드 2를 보지 못 foo하거나 더 이상 절반 만 변경 될 수 있습니다. 이것은 논리적으로 기대하는 것이 아닙니다.

다시 말하지만, 이것은 Java에서 사소한 주제입니다. 자세한 내용을 보려면 SO 및 인터 웹에 대한 다음 주제를 탐색하십시오.

"Brian Goetz" 라는 이름 이 뇌의 "동시성" 이라는 용어와 영구적으로 연관 될 때까지 이러한 주제를 계속 탐색하십시오 .


71
따라서 기본적 으로이 동기화 키워드는 메소드를 스레드로부터 안전합니까?
Rigo Vides

82
동기화 된 키워드는 코드 스레드를 안전하게 만드는 도구 중 하나입니다. 메소드 또는 변수 자체에서 동기화 된 것을 사용하면 트릭을 수행하거나 수행하지 않을 수 있습니다. 동시성을 올바르게 사용하려면 Java 메모리 모델에 대한 기본적인 이해가 중요합니다.
Stu Thompson

28
Brian Goetz (또는 Jon Skeet)가 아닌 한 언어 기본 (동기화, 휘발성) 만 사용하여 Java 동시성을 올바르게 얻는 것은 거의 불가능합니다. 우선, java.util.concurrent 패키지를 사용하고 그 위에 빌드하십시오.
Thilo

12
더 명확하게 : 동기화 된 메소드는 여러 스레드에서 동시에 호출 할 수 없습니다.
peterh-Reinstate Monica

2
@peterh 동기화는 그 이상을 수행하므로 자세한 설명이 필요합니다.
Stu Thompson

293

글쎄, 우리는 충분한 이론적 설명을 가지고 있다고 생각 하므로이 코드를 고려하십시오.

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모든 스레드가 없으면 이 메소드에 동시에 액세스 할 수 있습니다.

스레드가 오브젝트의 동기화 된 메소드 'test'(여기서 오브젝트는 'TheDemo'클래스의 인스턴스 임)를 호출 할 때 해당 오브젝트의 잠금을 획득하면 새 스레드는 이전 스레드와 동일한 오브젝트의 동기화 된 메소드를 호출 할 수 없습니다 잠금을 획득 한 잠금은 해제되지 않습니다.

클래스의 정적 동기화 메소드가 호출 될 때도 비슷한 일이 발생합니다. 스레드는 클래스와 연관된 잠금을 획득합니다 (이 경우 해당 클래스 인스턴스의 정적이 아닌 동기화 된 메소드는 해당 오브젝트 레벨 잠금이 여전히 사용 가능하므로 스레드에 의해 호출 될 수 있음). 클래스 레벨 잠금이 현재 잠금을 보유한 스레드에 의해 해제되지 않는 한 다른 스레드는 클래스의 정적 동기화 메소드를 호출 할 수 없습니다.

동기화 된 출력

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

7
좋은 예는 이론을 아는 것이 좋지만 코드는 항상 더 구체적이고 완전합니다.
Santi Iglesias

2
@SantiIglesias "완료"? 아니. 이 예는의 잠금 동작을 보여 synchronized주지만 메모리 일관성은 무시됩니다.
Stu Thompson

2
@Stu 톰슨 메모리 일관성 로크 결과
Dheeraj Sachan

@DheerajSachan 그 논리에 의해 ReentrantLock을 사용하면 메모리 일관성이 생깁니다. 그렇지 않습니다.
Stu Thompson

3
@boltup_im_coding : start () 메소드는 스레드를 "RUNNABLE"상태로 전환하여 실행할 준비가되었거나 이미 실행 중임을 나타냅니다. Runnable 상태의 다른 스레드 (보통 우선 순위가 높은 것은 아님)가 큐를 점프하여 실행을 시작할 수 있습니다. 위의 예에서, THREAD 3은 THREAD 2 이전에 CPU를 얻었습니다.
Sahil J

116

synchronized키워드는 여러 스레드에 의해 코드 또는 객체의 블록에 대한 동시 액세스를 방지합니다. 모든 방법이 Hashtable있다 synchronized그래서 한 번에 하나의 스레드 만에 그 중 하나를 실행할 수 있습니다.

synchronized와 같은 구문 이외의 구문을 사용 HashMap하는 경우 일관성 오류를 방지하기 위해 코드에 스레드 안전 기능을 빌드해야합니다.


81

synchronized다중 스레드 환경에서, synchronized메소드 / 블록을 갖는 객체 는 두 스레드가 synchronized동시에 코드 의 메소드 / 블록 에 액세스하는 것을 허용하지 않습니다 . 즉, 한 스레드는 읽을 수없고 다른 스레드는이를 업데이트 할 수 없습니다.

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

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


54

synchronized키워드 방식을 입력 할 때 (이 정적 메소드가 아니면, 지정된 객체 인스턴스에 대한) 단 하나 개의 스레드가 동시에 상기 방법을 실행할 수 있도록하는 것이, 로크를 획득하기 위해 스레드를 야기한다.

이것을 클래스 안전 스레드 만들기라고 부르지 만 이것이 완곡주의라고 말할 것입니다. 동기화가 Vector의 내부 상태가 손상되는 것을 방지하는 것은 사실이지만 일반적으로 Vector 사용자에게 큰 도움이되지는 않습니다.

이걸 고려하세요:

 if (vector.isEmpty()){
     vector.add(data);
 }

관련된 메소드는 동기화되어 있지만 개별적으로 잠금 및 잠금 해제되어 있기 때문에 불행하게도 시간이 걸리는 두 개의 스레드가 두 개의 요소로 벡터를 만들 수 있습니다.

따라서 실제로 응용 프로그램 코드에서도 동기화해야합니다.

메소드 레벨 동기화는 a) 필요하지 않을 때 비싸고 b) 동기화가 필요할 때 불충분하기 때문에 동기화되지 않은 대체 (Vector의 경우 ArrayList)가 있습니다.

최근에는 멀티 스레딩 문제를 처리하는 많은 영리한 유틸리티와 함께 ​​동시성 패키지가 릴리스되었습니다.


26

개요

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

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

더 깊은

구문 측면에서 synchronized키워드는 Object매개 변수 ( lock 객체 라고 함)를 취한 다음 뒤에을 붙 { block of code }입니다.

  • 실행시이 키워드가 발생하면 현재 스레드는 잠금 개체 를 "잠금 / 취득 / 소유"(선택)하고 잠금 이 획득 된 후 관련 코드 블록을 실행 하려고합니다 .

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

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

동기화 된 방법 :

추가 synchronized메소드 정의하면 키워드와 동기 코드 블록에서 전체 랩핑 방법 본체 같다 로크 대상의 존재 this (예 방법의 경우)ClassInQuestion.getClass() (클래스 메소드) .

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

인위적인

동기화가 없으면 읽기 및 쓰기 순서가 보장되지 않아 변수에 가비지가 남을 수 있습니다.
예를 들어 변수는 한 스레드가 쓴 비트의 절반과 다른 스레드가 쓴 비트의 절반으로 끝나서 스레드 중 어느 것도 쓰지 않았지만 두 가지가 혼잡 한 상태로 변수를 남길 수 있습니다.

하드웨어가 변수의 값을 캐시 할 수 있고 읽기 스레드가 작성된 값 대신 캐시 된 값을 볼 수 있기 때문에 다른 스레드가 읽기 전에 (벽 시계 시간) 스레드에서 쓰기 조작을 완료하는 것만으로는 충분하지 않습니다. 그것.

결론

따라서 Java의 경우 스레딩 오류가 발생하지 않도록 Java 메모리 모델을 따라야합니다.
다시 말해 : 후드 아래에서 동기화, 원 자성 작업 또는 클래스를 사용하는 클래스를 사용하십시오.

출처

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


죄송하지만이 예제가 있는데 그 의미를 이해하지 못합니다.`Integer i1 = Arrays.asList (1,2,3,4,5) .stream (). findAny (). get (); synchronized (i1) {정수 i2 = Arrays.asList (6,7,8,9,10) .parallelStream () .sorted () .findAny (). get (); System.out.println (i1 + ""+ i2); }`1. 왜 첫 번째 인스턴스에서 블록을 호출했으며이 호출이 코드에 영향을 미치지 않습니까? 두 번째 인스턴스는 첫 번째 블록의 호출에도 불구하고 스레드로부터 안전합니까?
Adryr83

1
@ Adryr83 질문이 있으시면 새 질문을 게시하여 질문하실 수 있습니다. 그러나 우리가 여기 있기 때문에 내가 할 수있는 것을 파싱 할 것입니다 (귀하의 질문은 이해하기 약간 어렵습니다). 해당 코드에 대해 알 수 있듯이 동기화가 필요한 것은 포함되어 있지 않습니다. 상황에 맞지 않습니다. 제안 : 가능하면 코드를 더 작은 개별 조각으로 나누고 그에 대한 답변을 검색하십시오. 하나의 큰 코드 블록을 파악하는 것보다 작고 고립 된 문제를 이해하는 것이 훨씬 쉽습니다.
Gima

21

축구장에서 볼 수 있듯이 일종의 개찰구라고 생각하십시오. 들어오고 자하는 사람들의 평행 증기가 있지만 개찰구에서 그들은 '동기화'됩니다. 한 번에 한 사람 만 통과 할 수 있습니다. 극복하기를 원하는 모든 사람들이 할 것이지만, 통과 할 때까지 기다려야 할 수도 있습니다.


16

동기화 된 키워드 란 무엇입니까?

스레드는 주로 필드에 대한 액세스를 공유하여 통신하며 개체 참조 필드가 참조합니다. 이 통신 방식은 매우 효율적이지만 스레드 간섭 및 메모리 일관성 오류 라는 두 가지 유형의 오류가 발생할 수 있습니다 . 이러한 오류를 방지하는 데 필요한 도구는 동기화입니다.

동기화 된 블록 또는 방법은 스레드 간섭을 방지하고 데이터의 일관성을 유지합니다. 어느 시점에서든 하나의 스레드 만 잠금을 획득하여 동기화 된 블록 또는 방법 ( 중요 섹션 )에 액세스 할 수 있습니다 . 다른 스레드는 중요한 섹션 에 액세스하기 위해 잠금 해제를 기다립니다 .

메소드는 언제 동기화됩니까?

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

문법적으로나 논리적으로 무슨 뜻입니까?

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

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

Java 문서 페이지 에서 자세한 내용

본질 잠금 및 동기화 :

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

모든 객체에는 관련된 고유 잠금이 있습니다 . 일반적으로 객체 필드에 독점적이고 일관된 액세스가 필요한 스레드는 객체에 액세스하기 전에 객체의 본질적 잠금을 획득 한 다음 완료되면 본질적 잠금을 해제해야합니다.

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

스레드가 내장 잠금을 해제하면 해당 조치와 동일한 잠금의 후속 획득간에 발생 전 관계가 설정됩니다.

메소드를 동기화하는 데는 두 가지 효과가 있습니다 .

첫째, 동일한 객체에서 동기화 된 메소드를 두 번 호출하여 인터리브 할 수 없습니다.

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

둘째, 동기화 된 메소드가 종료되면 동일한 오브젝트에 대한 동기화 된 메소드의 후속 호출과의 사전 관계를 자동으로 설정합니다.

이렇게하면 객체 상태에 대한 변경 사항이 모든 스레드에 표시됩니다.

다음에서 동기화에 대한 다른 대안을 찾으십시오.

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


11

Synchronized normal method상응하는 Synchronized statement(이 사용)

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

    equivalent to

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

Synchronized static methodSynchronized statement(사용 클래스) 와 동등

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 Methods와 비슷 Synchronized Statements하므로 이해해야 Synchronized Statements합니다.

=> 기본적으로 우리는

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

이해하는 데 도움이되는 2 가지 생각이 있습니다. synchronized

  • 모든 객체 / 클래스는 intrinsic lock관련되어 있습니다.
  • 스레드가 a를 호출하면 해당 객체에 synchronized statement대한를 자동으로 획득 하여 메소드가 반환 될 때 해제합니다. 한 스레드가 소유으로 , 다른 스레드는 얻을 수 없다 SAME 잠금 => 스레드 금고.intrinsic locksynchronized statement'sintrinsic lock

=> thread A호출 할 때 synchronized(this){// code 1}=> SAME 잠금으로 인해 synchronized(this)모든 블록 코드 (클래스 내부) 와 모든 synchronized normal method(클래스 내부)이 잠 깁니다. 잠금 해제 후 실행됩니다 ( "// code 1"완료). thread A

이 동작은 유사하다 synchronized(a variable){// code 1}synchronized(class).

SAME LOCK => lock (어떤 방법에 의존하지 않습니까?

동기화 된 메소드 또는 명령문을 사용 하시겠습니까?

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

그러나 동기화 방법을 적용하는 것은 간단하고 코드는 단순 해 보입니다. 일부 클래스의 경우 하나의 동기화 된 메소드 또는 클래스와 관련된 모든 동기화 된 메소드 만 있습니다 => synchronized method코드를 더 짧고 이해하기 쉽게 만드는 데 사용할 수 있습니다

노트

(와 관련이 많지 않으므로 synchronized객체와 클래스가 다르거 나 정적 및 정적이 아닙니다).

  • 당신이 사용하는 경우 synchronized또는 정상적인 방법이나 synchronized(this)또는 synchronized(non-static variable)각 객체 인스턴스에 기반을 동기화합니다.
  • 당신이 사용하는 경우 synchronized또는 정적 방법 또는 synchronized(class)또는 synchronized(static variable)이 클래스에 기반을 동기화합니다

참고

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

도움이되기를 바랍니다.


11

다음은 The Java Tutorials의 설명 입니다.

다음 코드를 고려하십시오.

public class SynchronizedCounter {
    private int c = 0;

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

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

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

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

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

9

동기화 된 기본적으로 컴파일러가 메소드 주위에 monitor.enter 및 monitor.exit를 작성한다는 것을 의미합니다. 따라서 사용 방법에 따라 스레드 안전 할 수 있습니다 (즉, 클래스의 기능에 따라 스레드 안전하지 않은 동기화 된 메소드로 객체를 작성할 수 있음).


5

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

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

한마디로 : "메모리 동기화" 는 스레드를 시작하고 스레드가 종료 될 때 휘발성 변수를 읽고 모니터 잠금을 해제합니다 (동기화 된 블록 / 함수를 떠남) 등 "암호화"가 암시 적으로 발생합니다. ") 모든 작업은 해당 특정 작업 전에 수행됩니다. 위에서 언급 한 ConcurrentLinkedDeque의 경우, 문서는 "말한다":

메모리 일관성 효과 : 다른 동시 콜렉션과 마찬가지로, 오브젝트를 ConcurrentLinkedDeque에 배치하기 전에 스레드의 조치는 다른 스레드의 ConcurrentLinkedDeque에서 해당 요소를 액세스하거나 제거한 후에 발생 하는 조치 이전에 발생 합니다.

경험이없는 대부분의 Java 프로그래머는 그로 인해 주어진 시간이 많이 걸리기 때문에 이러한 암묵적인 동작은 다소 위험한 측면입니다. 그런 다음 Java가 다른 작업로드가있는 프로덕션에서 수행하는 "추정 된"작업을 수행하지 않은 후이 스레드를 갑자기 우연히 발견하고 동시성 문제를 테스트하기가 매우 어렵습니다.


3

동기화는 단순히 단일 객체와 연결된 경우 여러 스레드가 동기화 된 블록이 특정 객체에 사용되는 경우 더티 읽기 및 쓰기를 방지 할 수 있음을 의미합니다. 더 명확하게하기 위해 예를 들어 보겠습니다.

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

우리는 2 개의 MyRunnable 클래스 객체를 만들었습니다. runnable1은 스레드 1과 공유되고 스레드 3과 runnable2는 스레드 2와 공유됩니다. 이제 t1과 t3이 동기화되지 않고 시작될 때 PFB 출력은 스레드 1과 3 모두 스레드 2에 대한 var 값에 동시에 영향을 미치며 var는 자체 메모리를 가지고 있음을 나타냅니다.

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

스레드 3은 동기화를 사용하여 모든 시나리오에서 스레드 1이 완료 될 때까지 대기합니다. 스레드 1과 스레드 3이 공유하는 runnable1과 스레드 2 만 공유하는 runnable2에 두 개의 잠금이 있습니다.

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

동기화는 그 이상을 의미합니다. 메모리 장벽에 중대한 영향을 미칩니다.
user1050755

1

동기화 된 단순은 두 스레드가 동시에 블록 / 방법에 액세스 할 수 없음을 의미합니다. 클래스의 블록 / 메소드가 동기화되었다고하면 한 번에 하나의 스레드 만 액세스 할 수 있습니다. 내부적으로 액세스를 시도하는 스레드는 먼저 해당 객체를 잠그고이 잠금을 사용할 수없는 한 다른 스레드는 해당 클래스 인스턴스의 동기화 된 메서드 / 블록에 액세스 할 수 없습니다.

다른 스레드는 동기화되도록 정의되지 않은 동일한 객체의 메서드에 액세스 할 수 있습니다. 스레드는 다음을 호출하여 잠금을 해제 할 수 있습니다.

Object.wait()

0

synchronizedJava의 블록은 멀티 스레딩의 모니터입니다. synchronized동일한 객체 / 클래스를 가진 블록은 단일 스레드로만 실행될 수 있으며 다른 모든 스레드는 기다리고 있습니다. race condition여러 스레드가 동일한 변수를 업데이트하려고 할 때 상황을 도울 수 있습니다 (첫 번째 단계는 volatile정보 사용 )

Java 5[정보]synchronized 를 지원하여 확장happens-before

모니터의 잠금 해제 (동기화 블록 또는 메소드 종료)는 동일한 모니터의 모든 후속 잠금 (동기화 블록 또는 메소드 입력) 이전에 발생합니다.

다음 단계는 java.util.concurrent

휘발성 대 동기화


-6

synchronized는 메모리 불일치 및 스레드 간섭 오류를 피하기 위해 멀티 스레딩 환경에서 관계 전에 발생하는 데 사용되는 Java의 키워드입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.