IT

Java에서 로컬 변수 스레드가 안전한 이유

itgroup 2023. 1. 1. 11:10
반응형

Java에서 로컬 변수 스레드가 안전한 이유

자바에서 멀티스레딩을 읽다가 이걸 발견했어요

로컬 변수는 Java에서 스레드 세이프입니다.

그 후 로컬 변수가 스레드 세이프인 이유와 방법에 대해 생각해 왔습니다.

누가 좀 알려주세요.

스레드를 작성하면 자체 스택이 생성됩니다.2개의 스레드는 2개의 스택을 가지며 1개의 스레드는 다른 스레드와 스택을 공유하지 않습니다.

프로그램에 정의되어 있는 모든 로컬 변수에는 스택에 메모리가 할당됩니다(Jatin 주석과 같이 여기서의 memory는 객체의 참조값, 원시타입의 값을 의미합니다). (스레드에 의한 각 메서드 호출에 의해 스택프레임이 자체 스택에 생성됩니다).이 스레드에 의해 메서드 실행이 완료되는 즉시 스택프레임이 삭제됩니다.

개념을 이해하는데 도움이 될만한 좋은 강의가 유튜브에 있다.

로컬 변수는 각 스레드의 자체 스택에 저장됩니다.즉, 로컬 변수는 스레드 간에 공유되지 않습니다.이는 모든 로컬 프리미티브 변수가 스레드 세이프임을 의미합니다.

public void someMethod(){

   long threadSafeInt = 0;

   threadSafeInt++;
}

오브젝트에 대한 로컬 참조는 조금 다릅니다.참조 자체는 공유되지 않습니다.그러나 참조되는 개체는 각 쓰레드의 로컬 스택에 저장되지 않습니다.모든 개체는 공유 힙에 저장됩니다.로컬로 작성된 객체가 작성된 메서드를 벗어나지 않으면 스레드 세이프가 됩니다.실제로 이러한 메서드나 오브젝트가 전달된 오브젝트를 다른 스레드에서 사용할 수 있게 하지 않는 한 다른 메서드나 오브젝트에 전달할 수도 있습니다.

기능 정의와 같은 방법을 생각해 보십시오.두 스레드가 동일한 메서드를 실행하는 경우, 이 스레드는 전혀 관련이 없습니다.각 로컬 변수의 고유한 버전을 생성하여 서로 어떤 방식으로도 상호 작용할 수 없습니다.

변수가 로컬이 아닌 경우(클래스 수준에서 메서드 외부에 정의된 인스턴스 변수와 같음), 해당 변수는 메서드의 단일 실행이 아닌 인스턴스에 연결됩니다.이 경우 동일한 메서드를 실행하는 두 개의 스레드는 모두 하나의 변수를 인식하며 이는 스레드 안전하지 않습니다.

다음 두 가지 경우를 고려합니다.

public class NotThreadsafe {
    int x = 0;
    public int incrementX() {
        x++;
        return x;
    }
}

public class Threadsafe {
    public int getTwoTimesTwo() {
        int x = 1;
        x++;
        return x*x;
    }
}

는 같은 입니다.NotThreadsafex가 표시됩니다. 두 번째,두, 두 개의 스레드가 같은 할 수 있습니다. 왜냐하면 스레드가 x를 변경하려고 하기 때문입니다!두 번째, 두 개의 스레드가 같은 인스턴스에서 실행됩니다.Threadsafe완전히 다른 변수를 볼 수 있고 서로 영향을 줄 수 없습니다.

각 메서드 호출에는 자체 로컬 변수가 있으며, 메서드 호출은 단일 스레드에서 발생합니다.단일 스레드에 의해서만 갱신되는 변수는 본질적으로 스레드 세이프입니다.

, 정확히 어떤 의미인지 주의해 주십시오.변수에 대한 쓰기 자체는 스레드 세이프입니다.변수가 참조하는 오브젝트의 호출 메서드는 본질적으로 스레드 세이프하지 않습니다.개체의 변수를 직접 업데이트하는 경우에도 마찬가지입니다.

남바리 답안 같은 거 말고도.

아노이머스형 메서드에서 로컬 변수를 사용할 수 있다는 점을 지적하고 싶습니다.

이 메서드는 스레드 안전성이 저하될 수 있는 다른 스레드에서 호출될 수 있으므로 Java는 anoymous 유형에 사용되는 모든 로컬 변수를 강제로 final로 선언합니다.

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

public void nonCompilableMethod() {
    int i=0;
    for(int t=0; t<100; t++)
    {
      new Thread(new Runnable() {
                    public void run() {
                      i++; //compile error, i must be final:
                      //Cannot refer to a non-final variable i inside an
                      //inner class defined in a different method
                    }
       }).start();
     }
  }

만약 자바가 (C#이 "클로저"를 통해" 하는 것과 같이) 이것을 허용한다면 로컬 변수는 더 이상 모든 상황에서 스레드 세이프가 되지 않습니다. 「」의 값, 「」의 값.i에 있는 이 「」가 되는 되지 않습니다.100.

스레드에는 자체 스택이 있습니다.2개의 스레드는 2개의 스택을 가지며 1개의 스레드는 다른 스레드와 스택을 공유하지 않습니다.로컬 변수는 각 스레드의 자체 스택에 저장됩니다.즉, 로컬 변수는 스레드 간에 공유되지 않습니다.

기본적으로 Java에는 클래스 정보와 데이터를 저장하는 4가지 유형의 스토리지가 있습니다.

메서드 영역, Heap, JAVA 스택,PC

따라서 메서드 영역과 힙은 모든 스레드에서 공유되지만 각 스레드는 자체 JAVA 스택과 PC를 가지며 다른 스레드에서는 공유되지 않습니다.

Java의 각 메서드는 Stack frame으로 되어 있습니다.따라서 어떤 메서드가 스레드에 의해 호출되면 스택프레임이 JAVA Stack에 로드됩니다.해당 스택 프레임 및 관련된 오퍼랜드스택에 있는 모든 로컬 변수는 다른 사용자와 공유되지 않습니다.PC에는 메서드의 바이트 코드에서 실행할 다음 명령 정보가 있습니다.따라서 모든 로컬 변수는 스레드 세이프입니다.

@Weston씨도 좋은 답변을 드렸습니다.

로컬 변수의 Java 스레드 세이프

스레드 스택에는 로컬 변수만 저장됩니다.

로컬 변수:primitive type(예: int, long...)는 다음 위치에 저장됩니다.thread stack그 결과 다른 스레드에서는 액세스 할 수 없습니다.

로컬 변수:reference type(의 일부Object에는, 2개의 파트(주소)가 격납되어 있습니다.thread stack및 오브젝트(에 저장되어 있음)heap)

class MyRunnable implements Runnable() {
    public void run() {
        method1();
    }

    void method1() {
        int intPrimitive = 1;
    
        method2();
    }

    void method2() {
        MyObject1 myObject1 = new MyObject1();
    }
}

class MyObject1 {
    MyObject2 myObject2 = new MyObject2();
}

class MyObject2 {
    MyObject3 myObject3 = MyObject3.shared;
}

class MyObject3 {
    static MyObject3 shared = new MyObject3();

    boolean b = false;
}

여기에 이미지 설명 입력

[JVM 메모리 모델]

언급URL : https://stackoverflow.com/questions/12825847/why-are-local-variables-thread-safe-in-java

반응형