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


91

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

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

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

누군가 제발 알려주세요.


27
스택에 할당되기 때문입니다. 그리고 스레드는 스택을 공유하지 않습니다. 각각의 고유 한 ..
Rohit Jain

답변:


103

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

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

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


13
죄송합니다. 틀 렸습니다. 원시 지역 변수 만 스택에 저장됩니다. Rest 모든 변수는 힙에 저장됩니다. 스택을 할당 할 수있는 몇 가지 varibles 자바 7 도입 탈출 분석
Jatin

6
스택은 힙의 개체에 대한 참조 만 보유합니다. 스택이 지워지기 때문에 참조도 지워집니다. 따라서 가비지 컬렉션에 사용할 수 있습니다
Jatin 2013-04-17

6
@Jatin : 맞습니다. 메모리를 의미 할 때 객체에 대한 참조 값과 원시에 대한 값을 의미합니다 (초보 개발자도 객체가 힙에 있다는 것을 알고 있다고 생각합니다).
kosa 2014

2
@Nambari이지만 참조 값이 공유 변수를 가리키는 경우. 그러면 스레드로부터 안전하다고 어떻게 말할 수 있습니까?
H.Rabiee

3
@hajder : 변수를 공유로 만드는 것은 무엇입니까? 거기에서 시작하십시오. 인스턴스 또는 클래스 변수가 맞습니까? 이 스레드에서 지역 변수가 아니라 Marko Toplink 답변을 읽으면 혼란스러워하는 점이라고 생각합니다.
kosa 2014-06-23

19

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

public void someMethod(){

   long threadSafeInt = 0;

   threadSafeInt++;
}

객체에 대한 로컬 참조는 약간 다릅니다. 참조 자체는 공유되지 않습니다. 그러나 참조 된 객체는 각 스레드의 로컬 스택에 저장되지 않습니다. 모든 개체는 공유 힙에 저장됩니다. 로컬에서 생성 된 객체가 생성 된 메서드를 이스케이프하지 않는 경우 스레드로부터 안전합니다. 실제로 이러한 메서드 나 개체 중 어느 것도 다른 스레드에서 전달 된 개체를 사용할 수없는 한 다른 메서드 및 개체에 전달할 수도 있습니다.


agrument에 실수가 있습니다. @Nambari 응답의 댓글을보세요
Jatin

localSafeInt가 항상 0이 될 것이라는 사실을 지적하고 있다면 1이고 어쨌든 삭제하면 좋습니다. 따라서이 변수는 스레드간에 공유되지 않으므로 멀티 스레딩의 영향을받지 않습니다. 스레드
세이프

14

기능 정의와 같은 방법을 생각하십시오. 두 스레드가 동일한 메서드를 실행하면 전혀 관련이 없습니다. 그들은 각각 각 지역 변수의 고유 한 버전을 만들고 어떤 식 으로든 서로 상호 작용할 수 없습니다.

변수가 로컬이 아닌 경우 (예 : 클래스 수준에서 메서드 외부에 정의 된 인스턴스 변수), 메서드의 단일 실행이 아닌 인스턴스에 연결됩니다. 이 경우 동일한 메서드를 실행하는 두 개의 스레드는 둘 다 하나의 변수를 볼 수 있으며 스레드로부터 안전하지 않습니다.

다음 두 가지 경우를 고려하십시오.

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는 완전히 다른 변수를 보게되며 서로 영향을 미칠 수 없습니다.


6

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

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


1
"참조하는 객체에 대한 메서드 호출은 본질적으로 스레드로부터 안전하지 않습니다"라고 말합니다. 그러나 메서드 로컬 참조가 참조하는 객체 (이 메서드 범위에서 인스턴스화 됨)는 어떻게 두 스레드에서 공유 할 수 있습니까? 예를 들어 지적 해 주시겠습니까?
Akshay Lokur 2014 년

1
지역 변수는 질문의 일부가 아닌 메서드 범위 내에서 인스턴스화 된 개체를 보유하거나 보유하지 않을 수 있습니다. 그렇더라도 메서드는 공유 상태에 액세스 할 수 있습니다.
Marko Topolnik 2014 년

6

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.


안녕하세요 Weston, 위의 토론과 아래 ​​답변에서 Java가 모든 지역 변수에 대한 스레드 안전성을 보장한다는 것을 이해했습니다. 그렇다면 동기화 된 키워드의 실제 사용이 무엇인지 알 수 있습니까? 이와 같은 예를 들어 설명해 주시겠습니까?
Prabhu

5

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


3

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

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

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

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

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


1

지역 변수는 스레드 스택에 저장됩니다.

지역 변수 입니다 primitive type(예 : INT, 긴 ...)를에 저장되어 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;
}

여기에 이미지 설명 입력

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