[java] Java에서 지역 변수가 스레드로부터 안전한 이유

나는 자바에서 멀티 스레딩을 읽고 있었고 이것을 발견했습니다.

지역 변수는 Java에서 스레드로부터 안전합니다.

그 이후로 나는 어떻게 / 왜 지역 변수가 스레드로부터 안전하다고 생각하고 있습니다.

누군가 제발 알려주세요.



답변

스레드를 생성하면 자체 스택이 생성됩니다. 두 개의 스레드에는 두 개의 스택이 있으며 하나의 스레드는 다른 스레드와 스택을 공유하지 않습니다.

프로그램에 정의 된 모든 지역 변수는 스택에 메모리가 할당됩니다 (Jatin이 언급했듯이 여기서 메모리는 객체에 대한 참조 값 및 기본 유형에 대한 값을 의미합니다) (스레드에 의한 각 메서드 호출은 자체 스택에 스택 프레임을 생성합니다). 이 스레드에 의해 메서드 실행이 완료되면 스택 프레임이 제거됩니다.

이 개념을 이해하는 데 도움이 될 수 있는 YouTube의 스탠포드 교수의 훌륭한 강의가 있습니다.


답변

지역 변수는 각 스레드의 자체 스택에 저장됩니다. 즉, 로컬 변수는 스레드간에 공유되지 않습니다. 이는 또한 모든 로컬 기본 변수가 스레드로부터 안전함을 의미합니다.

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;
    }
}

첫 번째에서 동일한 인스턴스에서 실행되는 두 개의 스레드 NotThreadsafe는 동일한 x를 보게됩니다. 스레드가 x를 변경하려고하기 때문에 위험 할 수 있습니다! 두 번째로 동일한 인스턴스에서 실행되는 두 개의 스레드 Threadsafe는 완전히 다른 변수를 보게되며 서로 영향을 미칠 수 없습니다.


답변

각 메서드 호출에는 고유 한 지역 변수가 있으며 분명히 메서드 호출은 단일 스레드에서 발생합니다. 단일 스레드에 의해서만 업데이트되는 변수는 본질적으로 스레드로부터 안전합니다.

그러나 이것이 정확히 무엇을 의미하는지 주시 하십시오. 변수 자체에 대한 쓰기 스레드로부터 안전합니다. 참조하는 객체에서 메서드를 호출하는 것은 본질적으로 스레드로부터 안전하지 않습니다 . 객체의 변수를 직접 업데이트하는 경우에도 마찬가지입니다.


답변

Nambari와 같은 다른 답변 외에도.

귀찮은 유형 메서드에서 지역 변수를 사용할 수 있음을 지적하고 싶습니다.

이 메소드는 스레드 안전성을 손상시킬 수있는 다른 스레드에서 호출 될 수 있으므로 Java는 성가신 유형에서 사용되는 모든 지역 변수를 최종적으로 선언하도록 강제합니다.

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

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.


답변

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


답변

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

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

그래서 메소드 영역과 힙은 모든 스레드에서 공유되지만 모든 스레드는 자체 JAVA 스택과 PC를 가지고 있으며 다른 스레드에서는 공유하지 않습니다.

Java의 각 메소드는 스택 프레임입니다. 따라서 스레드가 하나의 메소드를 호출하면 스택 프레임이 JAVA 스택에로드되고 해당 스택 프레임 및 관련 피연산자 스택에있는 모든 로컬 변수는 다른 사용자가 공유하지 않습니다. PC는 메소드의 바이트 코드에서 실행할 다음 명령어 정보를 갖게됩니다. 따라서 모든 지역 변수는 THREAD SAFE입니다.

@Weston도 좋은 답변을 제공했습니다.