简体   繁体   English

跨线程的对象可见性

[英]Object visibility across threads

I have a general doubt regarding publishing data and data changes across threads. 对于跨线程发布数据和数据更改,我有一个普遍的疑问。 Consider for example the following class. 例如考虑以下课程。

public class DataRace {
  static int a = 0;

  public static void main() {
    new MyThread().start();
    a = 1;
  }

  public static class MyThread extends Thread {
    public void run() { 
      // Access a, b.
    }
  }
}

Lets focus on main(). 让我们专注于main()。

Clearly 明确地

new MyThread().start();
a = 1;

There we change the shared variable a after the MyThread is started and thus may not be a thread-safe publication. 在MyThread启动之后,我们在那里更改了共享变量a,因此可能不是线程安全的发布。

a = 1;
new MyThread().start();

However this time the change in a is safely published across the new thread, since Java Language Specification (JLS) guarantees that all variables that were visible to a thread A when it starts a thread B are visible to thread B, which is effectively like having an implicit synchronization in Thread.start(). 但是,这次Java中的更改将安全地发布到新线程中,因为Java语言规范(JLS)保证了线程A在启动线程B时对线程A可见的所有变量对于线程B都是可见的,这实际上就像Thread.start()中的隐式同步。

new MyThread().start();
int b = 1;

In this case when a new variable is allocated after both the threads have been spawned, is there any guarantee that that the new variable will be safely published to all threads. 在这种情况下,当在两个线程都生成后分配了新变量时,是否可以保证新变量将安全地发布到所有线程。 ie if var b is accessed by the other thread, is it guaranteed to see its value as 1. Note that I'm not talking about any subsequent modifications to b after this (which certainly needs to be synchronized), but the first allocation done by the jvm. 例如,如果var b被另一个线程访问,是否保证将其值视为1。请注意,在此之后,我并不是在谈论对b的任何后续修改(当然需要同步),而是完成了第一个分配由jvm。

Thanks, 谢谢,

I wasn't not entirely sure about this one: 我对此并不完全确定:

a = 1;
new MyThread().start();

... in that I wasn't sure there was any guarantee that the value of a would be "flushed" to shared memory before the new thread started. ...因为我不确定在新线程启动之前,不能保证a的值会“冲刷”到共享内存中。 However, the spec explicitly talks about this. 但是,规范明确讨论了这一点。 In section 17.4.4 it states: 第17.4.4节中指出:

An action that starts a thread synchronizes-with the first action in the thread it starts. 启动线程的动作与它启动的线程中的第一个动作同步。

(The discussion after that basically shows that it'll be okay.) (此后的讨论基本上表明没问题。)

I'm not sure what your last example (with b ) is meant to be about. 我不确定您的最后一个示例(带有b )的含义。

I'm not sure what you're asking here. 我不确定您在这里问什么。 I think you're talking about thread-safe access to the "a" variable. 认为您是在谈论对“ a”变量的线程安全访问。

The issue is not the order of invocation but the fact that 问题不是调用的顺序,而是事实

-access to a is not threadsafe. -访问a不是线程安全的。 So in an example with multiple threads updating and reading a, you won't ever be able to guarantee that the "a" you're reading is the same value as what you updated from (some other thread may have changed the value). 因此,在有多个线程更新并读取a的示例中,您将永远无法保证所读取的“ a”值与更新后的值相同(某些其他线程可能已更改了该值)。

-in a multithreaded environment the jvm does not guarantee that the updated values for a are kept in sync. -在多线程环境中,jvm不保证a的更新值保持同步。 Eg 例如

Thread 1: a=1

Thread 2: a=2

Thread 1: print a <- may return 1

You can avoid this by declaring a "volatile". 您可以通过声明“ volatile”来避免这种情况。

As written there are no guarantees at all about the value of a. 如所写,a的值根本无法保证。

BTW, Josh Bloch's Concurrency in Practice is a great book on this subject ( and I say that not having gotten all the way through it yet ;) - it really helped me to understand just how involved threading issues can get. BTW,乔希布洛赫的实践并发是对这一问题的伟大的书(和我说,没有得到所有的方式,通过它尚未;) -它真的帮助我了解线程的问题,可以直接参与怎么弄。

If b is a local variable created within DataRace.main() as the code snippet indicates, it is not accessible to MyThread to begin with, so the question is moot. 如果b是在DataRace.main()中创建的局部变量(如代码片段所示),则MyThread首先无法访问它,因此问题无济于事。

If b is a shared variable between the main thread and the MyThread thread, it does not have the correct visibility in the absence of a proper memory barrier, so MyThread may not see the correct value promptly. 如果b是主线程和MyThread线程之间的共享变量,则在没有适当的内存屏障的情况下它没有正确的可见性,因此MyThread可能不会立即看到正确的值。

a = 1;
new MyThread().start();

The assignment to 'a' will happen before start is called on the new thread, so the new thread will always print the value '1' 对a的赋值将在新线程上调用start之前发生,因此新线程将始终打印值1。

new MyThread().start();
a = 1;

In this case, MyThread can print 1 or 0 as the value of 'a'. 在这种情况下,MyThread可以将1或0打印为'a'的值。

MyThread().start() starts a new thread that runs seperately. MyThread()。start()启动一个单独运行的新线程。 The declaration of int b = 1 has nothing to do with the thread that you started. int b = 1的声明与您启动的线程无关。 It continues in the main thread. 它在主线程中继续。

Thread safety is an issue if two threads read or mutate the same Object at the same time, or if two threads obtain locks on resources in reverse order, so that each one is waiting for the other one (this is called a deadlock). 如果两个线程同时读取或更改同一对象,或者两个线程以相反的顺序获取资源锁,则每个线程都在等待另一个线程(这称为死锁),则线程安全是一个问题。

I have my doubts about this question :) 我对此问题有疑问:)

Issues regarding access to shared resources between concurrent threads of execution is a fairly well understood and investigated topic. 关于在并发执行线程之间访问共享资源的问题是一个相当容易理解和研究的话题。

In general, if you have a source that is accessed with read/write semantics by a multiplicity of threads, you will need to regulate access to that resource. 通常,如果您有一个通过多个线程使用读/写语义访问的源,则需要调节对该资源的访问。 (Here the resource is the static int variable DataRace.a) (这里的资源是静态int变量DataRace.a)

(I also +1 Steve B.'s note here that the issue here is not the order of invocations.) (我也在这里+1了史蒂夫·B的注,这里的问题不是调用的顺序。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM