Java의 다중 스레드 환경에서 정적 메소드 동작


114

나를 괴롭 히고 내 마음 속에 몇 가지 논쟁을하는 간단한 어리석은 질문이 있습니다. 아래 질문에 대한 모든 의심을 버리고 싶습니다.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

5 개의 스레드가 각각 Clstest.testStaticMethod("arg-n")동시에 호출을 실행한다고 가정 해 보겠습니다 .

스레드 1은 Clstest.testStaticMethod("arg-1").

스레드 1이 섹션 1에 있으면 스레드 2가를 호출합니다 Clstest.testStaticMethod("arg-2").

그러면 스레드 1은 어떻게됩니까? 수면 상태가 될까요?

스레드 1이 일시 중지 된 섹션 1에서 실행을 재개 할 기회를 얻었을 때?

일이있을 때 어떻게됩니까 Clstest.testStaticMethod과 동일 Clstest.testStaticMethod다섯 개 스레드간에 공유?

inFileStr여러 스레드 에서 보낸 것을 교환 할 가능성이 있습니까?


어떤 언어를 타겟팅하고 있습니까?
ΩmegaMan 2013-06-27

3
@ OmegaMan : 그것은 자바입니다
namalfernandolk는

답변:


192

Hans Passant의 대답은 좋습니다. 그러나 나는 이것을 접하고 Java를 처음 접하는 사람을 위해 조금 더 간단한 수준에서 설명하려고 노력할 것이라고 생각했습니다. 여기 ..

자바의 메모리는 힙과 스택의 두 종류로 나뉩니다. 힙은 모든 객체가있는 곳이고 스택은 스레드가 작업을 수행하는 곳입니다. 각 스레드에는 자체 스택이 있으며 서로 스택에 액세스 할 수 없습니다. 각 스레드에는 현재 실행중인 코드 비트를 가리키는 코드에 대한 포인터도 있습니다.

스레드가 새 메서드를 실행하기 시작하면 해당 메서드의 인수와 지역 변수를 자체 스택에 저장합니다. 이러한 값 중 일부는 힙의 개체에 대한 포인터 일 수 있습니다. 두 스레드가 동시에 동일한 메서드를 실행하는 경우 둘 다 해당 메서드를 가리키는 코드 포인터가 있고 스택에 자체 인수 및 지역 변수 복사본이 있습니다. 스택의 사물이 힙의 동일한 객체를 가리키는 경우에만 서로 간섭합니다. 이 경우 모든 종류의 일이 발생할 수 있습니다. 그러나 Hans가 지적했듯이 문자열은 변경 불가능하므로 (변경할 수 없음) 이것이 "공유"되는 유일한 객체 인 경우 안전합니다.

너무 많은 스레드가 동일한 방법을 실행할 수 있습니다. 동시에 실행되지 않을 수도 있습니다. JVM이 하드웨어 스레드에 예약 된 OS 스레드에 Java 스레드를 매핑 할 때 시스템에있는 코어 수에 따라 다릅니다. 따라서 복잡한 동기화 메커니즘 을 사용하지 않고 이러한 스레드가 인터리브되는 방식을 거의 제어 할 수 없습니다 .

수면은 스레드가 자체적으로 수행하는 작업입니다.


3
따라서 멀티 코어 프로세서 환경에서 동일한 코드를 동시에 실행하는 여러 스레드가있을 수 있습니다. 그리고 단일 프로세서 환경에서는 주어진 시간에 하나의 스레드 만 실행됩니다. (여러 스레드가 그들 사이에서 시간을 공유합니다.) 그러면 스레드 스케쥴러가 현재 스레드 (A)에서 스레드 (B) 로의 기회를 줄 때 스레드 (A)가 일시 중지 된 위치에서 어떻게 다시 시작됩니까? 이력서 포인트를 어떻게 알 수 있습니까? 그 이유는 "각 스레드에도 현재 실행중인 코드를 가리키는 코드에 대한 포인터가 있습니까?" 당신이 말했듯이?
namalfernandolk 2015-06-27

6
당신은 그것을 얻었습니다. 몇 가지 요점을 명확히하기 위해 먼저 스레드가 예약되는 방식이 Java의 제어 범위를 벗어납니다. 여기서는 썬의 핫스팟 JVM에 대해 이야기하고 있습니다. JVM은 Java 스레드를 OS 스레드에 매핑하고 OS는 실행할 스레드를 결정합니다. 말했듯이 단일 코어 머신에서는 OS가 한 번에 하나만 실행할 수 있지만 멀티 코어 머신에서는 한 번에 둘 이상을 실행할 수 있습니다. 둘째, 스레드는 일시 중지되는시기를 실제로 인식하지 못합니다. 유일한 정보는 프로그램 포인터 (코드에 대한 포인터)와 스택뿐입니다.이 정보는 그대로 저장되고 복원됩니다.
selig

따라서 스레드 간 간섭은 스레드가 로컬 범위를 벗어난 변수를 사용할 때 발생하며, 예를 들어 다른 스레드가 자체 스택에서 해당 변수 (또는 변수에 대한 포인터)를 가져 오기 전에 한 스레드가 변수의 값을 업데이트합니까? 그게 올바른 이해입니까?
hariszhr

2
좀 더 정확하게 말하면 ... 간섭이 발생할 수 있고 발생할 수 있지만 반드시 발생하지는 않습니다 ... 스레드가 힙에서 사물을 공유 할 때 (로컬이 아님). 코드의 다른 부분 간의 종속성에 따라 간섭이 발생할 수있는 몇 가지 다른 방법이 있습니다. 누락 된 세부 정보가 있으므로 귀하의 예에 대해 잘 모르겠습니다. 스레드 A와 B가 모두 공유 값을 읽은 다음 둘 다 읽기 값을 기반으로 업데이트하는 잠재적 인 문제를 언급하고있을 수 있습니다. 이것은 데이터 경쟁입니다.
selig

1
@selig 인스턴스 메서드 만있는 클래스가있는 경우 예 : 서비스 클래스이고 싱글 톤이면 서비스 클래스가 상태를 보유하지 않으므로 한 번에 인스턴스 메서드를 실행하는 여러 스레드에 대해 걱정할 필요가 없습니다. 클래스에 인스턴스 변수가있는 경우에만 존재합니다. 내 이해가 맞습니까?
Yug Singh

67

수면 상태가 될까요?

아니요, 스레드 실행은 의도적으로 서로 동기화하지 않는 한 다른 스레드에 영향을주지 않습니다. 두 개 이상의 프로세서 코어가있는 경우 모든 최신 시스템에서 해당 스레드가 정확히 동시에 실행될 가능성이 높습니다. 머신에 코어가 충분하지 않을 수 있으므로 5 개의 스레드를 시작할 때 그 가능성이 약간 줄어 듭니다. 운영 체제는 둘 중 하나를 선택해야하므로 실행할 시간이 주어집니다. 스레드 스케줄러의 작업입니다. 그러면 스레드는 "휴면"상태가 아니며 단순히 일시 중지되고 스레드 스케줄러가 실행할 기회를주기를 기다립니다. 스케줄러에 의해 중단 된 위치에서 다시 시작됩니다.

여러 스레드에서 보낸 inFileStr을 교환 할 가능성이 있습니까?

그러한 가능성은 없으며 스레드에는 자체 스택이 있으므로 모든 메서드 인수와 지역 변수는 각 스레드에 대해 고유합니다. 또한 문자열을 사용하면 문자열 이 변경 불가능하므로 이러한 스레드가 서로 간섭 할 수 없습니다.

인수가 다른 종류의 변경 가능한 객체에 대한 참조이면 그러한 보장이 없습니다. 또는 메서드 자체가 정적 변수 나 힙의 개체에 대한 참조를 사용하는 경우. 스레드가 오브젝트를 수정하고 다른 스레드가이를 읽을 때 동기화가 필요합니다. C # 언어 의 lock 키워드는 이러한 필수 동기화를 구현하는 표준 방법입니다. 메서드가 정적 이라는 사실 은 이러한 동기화가 절대 필요하지 않음을 의미하지 않습니다. 그냥 덜 동일한 개체를 (공유 액세스하는 스레드에 대해 걱정할 필요가 없기 때문에 ).


3
죄송합니다. [java] 태그를 본 적이 없습니다. 충분히 가깝습니다.
Hans Passant 2013-06-27

게시 할 때 추가하는 것을 잊었습니다. 내 잘못이야. :). 어쨌든 대답 해 주셔서 감사합니다. 매우 도움이되었습니다.
namalfernandolk 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.