Sam*_*ire 1 java multithreading
我编写多线程软件,但我对 Java 有一些不明白的地方。
我的理解是Java对象共享内存地址空间。因此任意数量的线程都可以查看和访问任意数量的对象。
如果我在主线程中创建线程并将构造函数中的对象传递给每个线程,则 Java 解释器不会在线程之间进行编组。
Java 如何强制 Java 程序的内存模型是线程安全的并且不会看到部分对象构造?
换句话说,如果程序的构造函数正在运行,那么在创建对象时如何阻止内存模型无效?当然,我承认没有人可以引用正在构造的对象。但是Java的簿记必须将对象存储在内存中,并且需要是线程安全的。
我的理解是Java对象共享内存地址空间。因此任意数量的线程都可以查看和访问任意数量的对象。
是的,他们可以看到正确分配和构造的对象,他们引用了. Java 线程不能在没有引用的情况下从堆内存中随机抓取对象。通过线程安全设计,低级 JVM 内部不会这样做。
如果我在主线程中创建线程并将构造函数中的对象传递给每个线程,则 Java 解释器不会在线程之间进行编组。
是的,在 Java 语言级别,您可以在构造函数中泄漏this。这是一种搬起石头砸自己脚的特定方式,相反,您可以通过在对象准备好之前不泄漏对象引用来避免搬起石头砸自己的脚。
正如 Basil Bourque 在评论中指出的那样,这是为什么构造函数通常应该简短而复杂的初始化可以从使用构建器模式中受益的另一个因素。
Java 如何强制 Java 程序的内存模型是线程安全的并且不会看到部分对象构造?
低级堆管理机制是线程安全的,因为它以线程安全的方式分配堆内存块,并以线程安全的方式对它们进行垃圾收集。考虑大约同时从两个线程进行以下构造函数调用:
someclass x = new someclass();
Run Code Online (Sandbox Code Playgroud)
0 new #1 // Class [someclass]
3 dup
4 invokespecial #4 // Method [someclass].<init>()V
7 areturn
Run Code Online (Sandbox Code Playgroud)
两个线程各自执行字节码new并获取未初始化的对象。由于低级堆分配机制是线程安全的,因此两个线程获得单独的对象。它们位于共享内存空间中这一事实是无关紧要的——它们仍然是单独的对象。
他们调用构造函数来初始化他们各自的对象——这仍然没问题。对象引用只能通过两种方式供 java 代码使用 - 要么在构造函数返回后赋值x,要么故意泄漏构造函数中的引用。即使您确实泄漏了对该对象的 Java 引用,该对象标头的实际低级分配和初始化也基本上已完成 -new字节码已经完成运行。
但是Java的簿记必须将对象存储在内存中,并且需要是线程安全的。
是的,确实如此。分配器是线程安全的,GC 是线程安全的,几乎所有其他低级对象访问都是为了响应您的 Java 代码尝试使用对象所拥有的引用对对象执行某些操作。
完全并发的 GC/分配器可以是符合规范的 JVM 的一部分。单线程/stop-the-world GC/分配器可以是符合规范的 JVM 的一部分(但该 JVM 的性能扩展可能很差)。当两个线程同时创建对象时破坏堆的分配器根本就被破坏了,而构建在它上面的 JVM 也被破坏了。