정적 클래스 변수를 수정하지 않으면 동기화되지 않은 정적 메소드가 스레드 안전합니까?


145

난 당신이하는 정적 방법이 있다면 궁금 하지 동기화를하지만 않습니다 하지 정적 변수를 수정할 수는 스레드 안전? 메소드가 그 안에 로컬 변수를 작성하면 어떨까요? 예를 들어 다음 코드는 스레드로부터 안전합니까?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

따라서 두 개의 스레드가 연속적으로 동시에 호출하는 두 개의 스레드가 있으면 하나는 개 ( "그레이트 데인"및 "불독")와 다른 하나는 고양이 ( "페르시아어"및 "샴")와 함께 고양이와 개를 얻습니다. 같은 배열에서? 아니면 고양이와 개가 동시에 같은 방법으로 호출되지 않습니까?


이 문제에 관한 또 다른 스레드 : stackoverflow.com/questions/8015797/…
象 嘉 道

2
그것은 다른 질문입니다. 이것은 정적 메소드 호출이 배열의 안전 여부가 아닌 스레드 안전인지 여부입니다.
썰매

답변:


212

이 방법은 100 % 스레드 안전합니다 static. 그렇지 않은 경우에도 마찬가지 입니다. 스레드 안전성 문제는 스레드간에 데이터를 공유해야 할 때 발생합니다. 원 자성, 가시성 등을 관리해야합니다.

이 메소드는 스택에 상주 하고 힙의 불변 오브젝트에 대한 참조 대해서만 매개 변수 에서만 작동 합니다 . 스택은 본질적으로 스레드에 로컬 이므로 데이터 공유가 발생하지 않습니다.

변경 불가능한 객체 ( String이 경우)도 일단 생성되면 변경할 수없고 모든 스레드가 동일한 값을 볼 수 있기 때문에 스레드로부터 안전합니다. 반면에 방법이 수락 가능 Date하면 (변경 가능) 문제가있을 수 있습니다. 두 개의 스레드가 동일한 객체 인스턴스를 동시에 수정하여 경쟁 조건 및 가시성 문제를 일으킬 수 있습니다.


4
정답. 메소드 레벨 변수는 각 스레드 실행 스택에 복제됩니다.
Sid

기술적으로이 방법은 인라인되고 매개 변수는 CPU 레지스터입니다. 그럼에도 불구하고 그 대답은 정확하다
bestsss

43
스택은 물론 현재 스레드에 국한되지만 해당 스택의 공유 객체에 대한 참조를 가질 수 있습니다. 이 예제에서는 문자열을 변경할 수 없기 때문에 문제가되지 않지만 전달 된 매개 변수를 수정하는 메서드는이 전달 된 개체에 여러 스레드에서 액세스 할 수있는 경우 스레드 안전성 문제가 발생할 수 있습니다.
Jörn Horstmann

1
@TomaszNurkiewicz가 언급했듯이 변경 가능한 객체 참조를 전달하면 경쟁 조건에 들어갈 수 있습니다. 메소드가 오브젝트를 변경하지 않더라도 이것이 사실입니까? 객체가 변경 가능했기 때문에 여전히 경쟁 조건으로 분류됩니까? 마지막 키워드를 매개 변수에 추가하면 어떻게 되나요?
Rafay

메소드에서 클래스 객체를 전달하면 어떻게됩니까? 스택이나 힙에 변수가 있습니까?
grep

28

메소드는 공유 상태가 변경 될 때만 스레드 안전하지 않을 수 있습니다. 정적인지 여부는 관련이 없습니다.


3
@Konrad_Garus 여기서 문제는 로컬 변수가 공유 상태를 구성하는지 아닌지 또는 정적 메서드의 스택이 스레드 당인지 공유인지에 대한 문제입니다.
Sled

"메소드는 공유 상태가 변경 될 때만 스레드 안전하지 않을 수 있습니다." 아니요, 공유 상태를 변경하지 않고 단순히 액세스하는 경우 스레드 안전하지 않을 수도 있습니다. 다른 스레드가 올바르게 동기화 된 경우에도 변경 가능한 개체에 대한 동기화되지 않은 액세스는 다른 스레드에 의해 개체가 변경되는 경우 일관성이없는 상태에 액세스 할 수 있습니다. 두 스레드 모두 스레드 안전성을 유지하려면 적절한 동기화가 필요합니다.
Warren Dew

12

이 기능은 완벽하게 스레드 안전합니다.

당신이 그것에 대해 생각한다면 ... 이것이 다르다면 어떻게 될지 가정하십시오. 모든 일반적인 함수는 동기화되지 않으면 스레딩 문제가 발생하므로 JDK의 모든 API 함수는 잠재적으로 여러 스레드에 의해 호출 될 수 있으므로 동기화되어야합니다. 대부분의 경우 앱에서 일부 API를 사용하므로 멀티 스레드 앱은 사실상 불가능합니다.

이것은 생각하기에는 너무 우스운 일이므로, 당신만을 위해 : 문제가 발생할 수있는 분명한 이유가 있다면 메소드는 스레드 안전하지 않습니다. 내 기능에 여러 스레드가있는 경우 무엇을 생각하고 단계 디버거가 있고 첫 번째 단계를 차례로 진행 한 다음 두 번째 스레드는 아마도 두 번째 스레드는 아마도 두 번째 스레드는 무엇인지 생각하십시오. 문제가 있습니까? 하나를 찾으면 스레드 안전하지 않습니다.

또한 ConcurrentHashMap과 같이 명시된 경우를 제외하고 대부분의 Java 1.5 Collection 클래스는 스레드로부터 안전하지 않습니다.

그리고 이것에 대해 자세히 알고 싶다면 휘발성 키워드와 모든 부작용을 자세히 살펴보십시오. java.util.Concurrent에서 Semaphore () 및 Lock () 클래스와 그 친구를 살펴보십시오. 클래스 주위의 모든 API 문서를 읽으십시오. 배우고 만족시키는 것도 가치가 있습니다.

이 정교하게 답변 해 주셔서 죄송합니다.


2
"생각해 보면 ... 이것이 다르다면 어떤 일이 일어날 지 가정 해 보자. 모든 일반적인 함수는 동기화되지 않으면 스레딩 문제가 발생하므로 JDK의 모든 API 함수는 잠재적으로 여러 개에 의해 호출 될 수 있기 때문에 동기화되어야한다. 스레드. " 좋은 지적!
Sled

1

static스레드간에 공유되는 정적 데이터를 수정하려면 동기화 된 정적 메소드와 함께 키워드를 사용하십시오 . static키워드를 사용하면 작성된 모든 스레드가 단일 버전의 메소드에 대해 경쟁합니다.

volatile동기화 된 인스턴스 메소드와 함께 키워드를 사용하면 각 스레드에 고유 한 공유 데이터 사본이 있으며 스레드간에 읽기 / 쓰기가 누출되지 않습니다.


0

변경 불가능한 문자열 객체는 위의 스레드 안전 시나리오의 또 다른 이유입니다. 대신 변경 가능한 객체 (예 : makeMutableArray ..)를 사용하면 스레드 안전성이 확실히 손상됩니다.


정적 메소드 호출이 다른 스레드에서 동일한 메소드에 대한 다른 호출의 인수를 볼 수 있는지 여부는 문제였습니다. 대답은 "아니오!"입니다. 나는 알고 있었지만 모호한 동료들에게 증명할 수 있기를 원했습니다.
Sled

이 응답이 다운 투표 된 이유는 무엇입니까? 다른 대답에 기여하지 않는 요점은 변경 가능성이 인바운드 또는 아웃 바운드 일 수 있다는 것입니다. 변경 가능 변수를 반환하면 스레드 안전 상태가 아닙니다. 그 질문은 그 의견이 제시하는 것만 큼 좁지 않다. 코드 샘플 이후의 확장 된 질문은 아마도 단위 테스트로 코드로 표현 될 수있었습니다. 그러나 나는 동료들을 설득하려고 애 쓰고 있습니다. "나나 내 테스트 코드 또는 Josh Bloch는 믿지 않지만 SO에 대한 답변을받을 수 있습니다."
som-snytt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.