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.