스레드간에 정적 변수가 공유됩니까?
스레딩에 대한 상위 수준의 Java 클래스의 선생님이 제가 확신 할 수없는 말을했습니다.
그는 다음 코드가 반드시 ready
변수를 업데이트하는 것은 아니라고 말했습니다 . 그에 따르면 두 스레드가 반드시 정적 변수를 ReaderThread
공유하는 것은 아닙니다. 다른 것을 업데이트하지 않습니다.
기본적으로 그는 ready
메인 스레드에서 업데이트 될 수 있지만 에서는 업데이트되지 ReaderThread
않으므로 ReaderThread
무한 반복됩니다.
그는 또한 프로그램이 0
또는 42
. 어떻게 42
인쇄 할 수 있는지 이해 하지만 0
. 그는 이것이 number
변수가 기본값으로 설정된 경우라고 언급했습니다 .
스레드간에 정적 변수가 업데이트된다는 것이 보장되지 않는다고 생각했지만, 이것은 Java에 대해 매우 이상합니다. ready
휘발성으로 만들면 이 문제가 해결됩니까?
그는 다음 코드를 보여주었습니다.
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready) Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
가시성과 관련하여 정적 변수에 특별한 것은 없습니다. 액세스 할 수있는 경우 모든 스레드가 접근 할 수 있으므로 더 많이 노출되기 때문에 동시성 문제가 발생할 가능성이 더 큽니다.
JVM의 메모리 모델로 인한 가시성 문제가 있습니다. 다음은 메모리 모델과 쓰기가 스레드에 어떻게 표시되는지에 대한 기사 입니다. 한 스레드가 적시에 다른 스레드에 표시되는 변경 사항을 믿을 수 없습니다 (실제로 JVM은 발생 전 관계 를 설정하지 않는 한 이러한 변경 사항을 모든 시간 프레임에 표시 할 의무가 없습니다). .
다음은 해당 링크의 인용문입니다 (Jed Wesley-Smith의 의견에 제공됨).
Java 언어 사양의 17 장은 공유 변수의 읽기 및 쓰기와 같은 메모리 작업에 대한 사전 발생 관계를 정의합니다. 한 스레드의 쓰기 결과는 읽기 작업 전에 쓰기 작업이 발생하는 경우에만 다른 스레드의 읽기에서 볼 수 있습니다. Thread.start () 및 Thread.join () 메서드뿐만 아니라 동기화 및 휘발성 구성은 발생 전 관계를 형성 할 수 있습니다. 특히:
스레드의 각 작업은 프로그램 순서에서 나중에 나오는 해당 스레드의 모든 작업보다 먼저 발생합니다.
모니터의 잠금 해제 (동기화 된 블록 또는 메소드 종료)는 동일한 모니터의 모든 후속 잠금 (동기화 된 블록 또는 메소드 항목) 전에 발생합니다. 그리고 전 발생 관계는 전이 적이므로 잠금 해제 전 스레드의 모든 작업은 해당 모니터의 스레드 잠금 이후의 모든 작업보다 먼저 발생합니다.
휘발성 필드에 대한 쓰기는 동일한 필드의 모든 후속 읽기 전에 발생합니다. 휘발성 필드의 쓰기 및 읽기는 모니터 진입 및 종료와 유사한 메모리 일관성 효과를 갖지만 상호 배제 잠금을 수반하지 않습니다.
스레드에서 시작하기위한 호출은 시작된 스레드에서 작업을 수행하기 전에 발생합니다.
스레드의 모든 작업은 다른 스레드가 해당 스레드의 조인에서 성공적으로 반환되기 전에 발생합니다.
그는 가시성 에 대해 이야기하고 있었고 너무 문자 그대로 받아 들여서는 안됩니다.
정적 변수는 실제로 스레드간에 공유되지만 한 스레드에서 변경된 내용이 다른 스레드에 즉시 표시되지 않을 수 있으므로 변수의 복사본이 두 개있는 것처럼 보입니다.
이 문서는 그가 정보를 제공 한 방법과 일치하는보기를 제공합니다.
먼저 Java 메모리 모델에 대해 약간 이해해야합니다. 나는 그것을 간단하고 잘 설명하기 위해 수년에 걸쳐 조금 고생했습니다. 오늘부터 제가 생각할 수있는 가장 좋은 방법은 다음과 같이 상상하는 것입니다.
Java의 각 스레드는 별도의 메모리 공간에서 발생합니다 (이것은 분명히 사실이 아니므로이 부분에 대해 저와 함께 참아주십시오).
메시지 전달 시스템에서와 같이 이러한 스레드간에 통신이 발생하도록 보장하려면 특수 메커니즘을 사용해야합니다.
Memory writes that happen in one thread can "leak through" and be seen by another thread, but this is by no means guaranteed. Without explicit communication, you can't guarantee which writes get seen by other threads, or even the order in which they get seen.
...
But again, this is simply a mental model to think about threading and volatile, not literally how the JVM works.
Basically it's true, but actually the problem is more complex. Visibility of shared data can be affected not only by CPU caches, but also by out-of-order execution of instructions.
Therefore Java defines a Memory Model, that states under which circumstances threads can see consistent state of the shared data.
In your particular case, adding volatile
guarantees visibility.
They are "shared" of course in the sense that they both refer to the same variable, but they don't necessarily see each other's updates. This is true for any variable, not just static.
And in theory, writes made by another thread can appear to be in a different order, unless the variables are declared volatile
or the writes are explicitly synchronized.
Within a single classloader, static fields are always shared. To explicitly scope data to threads, you'd want to use a facility like ThreadLocal
.
When you initialize static primitive type variable java default assigns a value for static variables
public static int i ;
when you define the variable like this the default value of i = 0; thats why there is a possibility to get you 0. then the main thread updates the value of boolean ready to true. since ready is a static variable , main thread and the other thread reference to the same memory address so the ready variable change. so the secondary thread get out from while loop and print value. when printing the value initialized value of number is 0. if the thread process has passed while loop before main thread update number variable. then there is a possibility to print 0
@dontocsata you can go back to your teacher and school him a little :)
few notes from the real world and regardless what you see or be told. Please NOTE, the words below are regarding this particular case in the exact order shown.
The following 2 variable will reside on the same cache line under virtually any know architecture.
private static boolean ready;
private static int number;
Thread.exit
(main thread) is guaranteed to exit and exit
is guaranteed to cause a memory fence, due to the thread group thread removal (and many other issues). (it's a synchronized call, and I see no single way to be implemented w/o the sync part since the ThreadGroup must terminate as well if no daemon threads are left, etc).
The started thread ReaderThread
is going to keep the process alive since it is not a daemon one! Thus ready
and number
will be flushed together (or the number before if a context switch occurs) and there is no real reason for reordering in this case at least I can't even think of one. You will need something truly weird to see anything but 42
. Again I do presume both static variables will be in the same cache line. I just can't imagine a cache line 4 bytes long OR a JVM that will not assign them in a continuous area (cache line).
참고URL : https://stackoverflow.com/questions/4934913/are-static-variables-shared-between-threads
'IT story' 카테고리의 다른 글
REST 웹 서비스에서 클라이언트로 파일을 보내는 올바른 방법은 무엇입니까? (0) | 2020.09.03 |
---|---|
PHP DateTime :: 달 더하기 및 빼기 수정 (0) | 2020.09.03 |
CSS3 미디어 쿼리에 Sass 변수 사용 (0) | 2020.09.03 |
파이썬에서 json.dump ()와 json.dumps ()의 차이점은 무엇입니까? (0) | 2020.09.03 |
.net에서 중첩 클래스를 사용해야하는 이유 / 언제? (0) | 2020.09.03 |