programing

정적 변수는 스레드 간에 공유됩니까?

itsource 2022. 10. 4. 21:54
반응형

정적 변수는 스레드 간에 공유됩니까?

스레드화에 관한 상위 레벨의 자바 수업에서 선생님이 내가 확신하지 못하는 말을 하셨다.

그는 다음 코드가 반드시 업데이트되는 것은 아니라고 말했다.ready변수.그에 따르면, 두 개의 스레드가 정적 변수를 공유할 필요는 없으며, 특히 각 스레드가 (메인 스레드와ReaderThread)는 독자적인 프로세서에서 동작하고 있기 때문에, 같은 레지스터/캐시등을 공유하지 않기 때문에, 한쪽의 CPU가 다른쪽의 CPU를 갱신하지 않습니다.

본질적으로, 그는 가능성이 있다고 말했다.ready메인 스레드에서는 갱신되지만,ReaderThread,하도록ReaderThread무한 루프합니다.

그는 또한 프로그램이 인쇄하는 것이 가능하다고 주장했다.0또는42어떻게 하는지 알겠다.42인쇄는 가능하지만 인쇄는 할 수 없다.0그가 말하길, 이 사건이 일어날 거라고 했어요numbervariable은 기본값으로 설정되어 있습니다.

스레드간에 static 변수가 갱신되는 것은 보증되지 않는다고 생각했습니다만, Java에서는 매우 이상하다고 생각됩니다.만들다readyvolatile 이 문제를 해결합니까?

그는 이 코드를 보여줬다.

public class NoVisibility {  
    private static boolean ready;  
    private static int number;  
    private static class ReaderThread extends Thread {   
        public void run() {  
            while (!ready)   Thread.yield();  
            System.out.println(number);  
        }  
    }  
    public static void main(String[] args) {  
        new ReaderThread().start();  
        number = 42;  
        ready = true;  
    }  
}

가시성에 관한 한 정적 변수에는 특별한 것이 없습니다.액세스 가능한 스레드가 있으면 스레드에 액세스 할 수 있기 때문에, 동시성 문제가 발생할 가능성이 높아집니다.

JVM의 메모리 모델에 의해 발생하는 가시성 문제가 있습니다.여기에서는 메모리 모델과 쓰기가 스레드에 표시되는 방법에 대해 설명합니다.occurs-before 관계를 설정하지 않는 한, 한 스레드가 다른 스레드에 시기적절하게 표시되도록 하는 변경 사항을 기대할 수 없습니다(실제로 JVM은 이러한 변경 사항을 시간 내에 사용자에게 표시할 의무가 없습니다).

다음은 링크의 인용문입니다(Jed Wesley-Smith의 코멘트로 제공).

Java Language Specification 17장에서는 공유 변수의 읽기 및 쓰기와 같은 메모리 작업에 대한 발생 전 관계를 정의합니다.한 스레드에 의한 쓰기 결과는 읽기 작업 전에 쓰기 작업이 발생한 경우에만 다른 스레드에 의한 읽기에 표시됩니다.동기 및 휘발성 구성 및 Thread.start() 메서드와 Thread.join() 메서드는 opens-before 관계를 형성할 수 있습니다.특히:

  • 스레드의 각 동작은 프로그램 순서 뒤에 오는 스레드의 모든 동작보다 먼저 발생합니다.

  • 모니터의 잠금 해제(동기화된 블록 또는 메서드 종료)는 동일한 모니터의 후속 잠금(동기화된 블록 또는 메서드 입력) 전에 발생합니다.또한 occurs-before 관계는 과도적이기 때문에 잠금 해제 전 스레드의 모든 동작은 가 모니터링하는 스레드 잠금 이후의 모든 동작 전에 발생합니다.

  • 휘발성 필드에 대한 쓰기는 같은 필드를 나중에 읽을 때마다 발생합니다.휘발성 필드의 쓰기 및 읽기는 모니터 입력 및 종료와 유사한 메모리 일관성 효과를 가지지만 상호 제외 잠금이 수반되지는 않습니다.

  • 스레드에서 시작하라는 호출은 시작된 스레드에서 작업이 수행되기 전에 발생합니다.

  • 스레드 내의 모든 작업은 다른 스레드가 해당 스레드의 결합에서 성공적으로 돌아오기 전에 수행됩니다.

그는 너무 문자 그대로 받아들여지지 말고 가시성에 대해 이야기하고 있었다.

정적 변수는 스레드 간에 공유되지만, 한 스레드에서 변경된 내용이 다른 스레드에 즉시 표시되지 않을 수 있으므로 변수의 복사본이 두 개 있는 것처럼 보일 수 있습니다.

이 문서에서는 그가 정보를 제공하는 방법과 일치하는 견해를 보여 줍니다.

먼저 Java 메모리 모델에 대해 조금 이해해야 합니다.나는 그것을 간결하고 잘 설명하기 위해 몇 년 동안 조금 애를 먹었다.현시점에서는 다음과 같이 생각할 수 있습니다.

  • Java의 각 스레드는 별도의 메모리 공간에서 발생합니다(이것은 명백히 사실이 아니므로 양해 바랍니다).

  • 메시지 전달 시스템에서처럼 이러한 스레드 간에 통신이 이루어지도록 하려면 특수한 메커니즘을 사용해야 합니다.

  • 한 스레드에서 발생하는 메모리 쓰기는 다른 스레드에 의해 "누락"되어 보일 수 있지만, 이는 결코 보장되지 않습니다.명확한 커뮤니케이션이 없으면 다른 스레드에서 어떤 쓰기가 표시되는지, 심지어 표시되는 순서도 보장할 수 없습니다.

...

thread model

하지만 다시 말씀드리지만, 이것은 JVM의 작동 방식이 아니라 스레드화와 휘발성에 대해 생각하는 단순한 정신 모델입니다.

기본적으로는 사실이지만, 실제로는 문제가 더 복잡합니다.공유 데이터의 가시성은 CPU 캐시뿐만 아니라 명령의 순서가 잘못된 실행에 의해서도 영향을 받을 수 있습니다.

따라서 Java는 공유 데이터의 일관된 상태를 스레드에서 확인할 수 있는 상황을 나타내는 메모리 모델을 정의합니다.

특정의 경우는,volatile가시성을 보증합니다.

물론 이 두 가지는 같은 변수를 참조한다는 점에서 "공유"되지만 서로의 업데이트를 볼 필요는 없습니다.이는 정적뿐만 아니라 모든 변수에 적용됩니다.

그리고 이론적으로 변수가 선언되지 않는 한 다른 스레드에 의해 작성된 쓰기는 다른 순서로 나타날 수 있습니다.volatile또는 쓰기가 명시적으로 동기화됩니다.

단일 클래스로더 내에서 스태틱필드는 항상 공유됩니다.데이터 범위를 스레드로 명시적으로 지정하려면 다음과 같은 기능을 사용할 수 있습니다.ThreadLocal.

static primitive type variable java default는 static 변수의 값을 할당합니다.

public static int i ;

이와 같이 변수를 정의하면 i = 0의 기본값입니다. 따라서 0을 얻을 수 있습니다. 그러면 메인 스레드는 true로 준비된 부울 값을 업데이트합니다.ready는 스태틱 변수, 메인 스레드 및 다른 스레드는 같은 메모리주소를 참조하기 때문에 ready 변수가 변경됩니다.따라서 secondary 스레드는 루프와 인쇄 값을 실행하는 동안 빠져나갑니다.스레드 프로세스가 메인 스레드 업데이트 번호 변수 앞에 루프하는 동안 통과된 경우, 숫자 초기화 값이 0인 경우.그러면 0을 출력할 수 있습니다.

@timeocsata 선생님한테 가서 조금 가르쳐도 돼:)

당신이 무엇을 보든, 무엇을 듣든, 현실 세계에서 나온 몇 가지 메모가 있습니다.아래 문구는 표시된 것과 동일한 순서로 이 건에 관한 것입니다.

다음 2개의 변수는 거의 모든 기존 아키텍처에서 동일한 캐시 라인에 존재합니다.

private static boolean ready;  
private static int number;  

Thread.exit(메인 스레드)는 반드시 종료되고exit는 스레드 그룹의 스레드 삭제(및 기타 많은 문제)로 인해 메모리펜스를 발생시키는 것이 보증됩니다.(이것은 동기화된 콜이며, 데몬 스레드 등이 남아 있지 않으면 스레드 그룹도 종료해야 하기 때문에 동기 부분과 함께 구현할 수 있는 유일한 방법은 없습니다).

시작된 스레드ReaderThread이 프로세스는 데몬이 아니기 때문에 활성화 됩니다.따라서ready그리고.number(또는 콘텍스트스위치가 발생했을 경우는 그 전의 수치)가 함께 플래시 됩니다.이 경우 적어도 어떤 것도 생각할 수 없습니다.뭔가 이상한 게 있어야 볼 수 있지만42. 다시 말씀드리지만 두 정적 변수가 동일한 캐시 행에 있을 것으로 추측됩니다.4바이트 길이의 캐시 라인이나 연속 영역(캐시 라인)에 할당되지 않는 JVM은 상상할 수 없습니다.

언급URL : https://stackoverflow.com/questions/4934913/are-static-variables-shared-between-threads

반응형