问题标签 [java-memory-model]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
850 浏览

java - How to test the backing array used in Java Sting?

While i was developing my Android application, my attention was caught by the backing array.

Multiple strings can share the same char[] because strings are immutable. The substring(int) method always returns a string that shares the backing array of its source string. Generally this is an optimization: fewer character arrays need to be allocated, and less copying is necessary. But this can also lead to unwanted heap retention. Taking a short substring of long string means that the long shared char[] won't be garbage until both strings are garbage. This typically happens when parsing small substrings out of a large input. To avoid this where necessary, call new String(longString.subString(...)). The string copy constructor always ensures that the backing array is no larger than necessary.

Then i have read many resources on the web. I know that Strings no longer shares the same backing array since jdk7u6, pointed by Mark Rotteveel.

Then i started trying to play with, and to test the existence of the shared backing array in my code:

First i assume == is a swallow equal comparison (isn't it?) that compares their memory locations (like what in C).

If they do share the same backing array, and == is just comparing their memory locations, both statements should return true (or at least the last one returns true).

However, they are both false.

Well, i think my laptop is having Java 7 update 21. (shown in Win7 -> Control Panel -> Java Control Panel -> About) (and also in Eclipse -> Window -> Preference -> Java -> Compiler -> Compiler compliance level: {1.3 , 1.4 , 1.5 , 1.6 , 1.7} )

And i know 1.7 means Java 7. And i know Java 7 is too high that the shared backing array may already have taken away. That is why i have asked Eclipse to compile my project with 1.5 and 1.6.

However, as i said, i am still getting false in those println()s.

Let me summarise my questions:

Q1) How to use Java codes to verify there is a use of underlying backing array? (other than making the OutOfMemoryError by millions of substring()s)

Q1) a. Is == sallow equal comparison?

Q1) b. Am i really using Java 5/6 to compile, if i set Compiler compliance level = 1.5/1.6?

Thanks for any input :-)

0 投票
5 回答
50131 浏览

java - Why does this Java program terminate despite that apparently it shouldn't (and didn't)?

A sensitive operation in my lab today went completely wrong. An actuator on an electron microscope went over its boundary, and after a chain of events I lost $12 million of equipment. I've narrowed down over 40K lines in the faulty module to this:

Some samples of the output I'm getting:

Since there isn't any floating point arithmetic here, and we all know signed integers behave well on overflow in Java, I'd think there's nothing wrong with this code. However, despite the output indicating that the program didn't reach the exit condition, it reached the exit condition (it was both reached and not reached?). Why?


I've noticed this doesn't happen in some environments. I'm on OpenJDK 6 on 64-bit Linux.

0 投票
3 回答
466 浏览

java - Java Puzzler:繁忙的等待线程停止工作

这是某种Java Puzzler,我偶然发现并无法真正解释。也许有人可以?

以下程序在短时间内挂起。有时在 2 次输出之后,有时在 80 次之后,但几乎总是在正确终止之前。如果第一次没有发生,您可能需要运行几次。

现在,很明显,繁忙的等待循环通常不是一个好主意。但这不是关于改进,而是关于了解正在发生的事情。

由于一切都按预期工作,WorkerThread.setWork()或者synchronized当该WorkerThread.workToDo字段设置为时,volatile我怀疑存在内存问题。

但究竟为什么会发生呢?调试无济于事,一旦您开始单步执行,一切都会按预期运行。

解释将不胜感激。

0 投票
1 回答
1810 浏览

android - android中的最大BackStack大小

我是android开发的新手。我需要知道androidBackStack最大内存大小 我想知道有多少Android 应用程序活动可以存储在 BackStack 中

谢谢

0 投票
1 回答
13386 浏览

java - 指令重新排序和发生之前的关系

在 Java Concurrency In Practice 一书中,我们多次被告知,程序的指令可以由编译器、运行时的 JVM 甚至处理器重新排序。所以我们应该假设执行的程序不会以与我们在源代码中指定的顺序完全相同的顺序执行其指令。

但是,讨论 Java 内存模型的最后一章提供了一系列发生前发生的规则,指示 JVM 保留了哪些指令顺序。这些规则中的第一个是:

  • “程序顺序规则。线程中的每个操作都发生在该线程中程序顺序后面的每个操作之前。”

我相信“程序顺序”是指源代码。

我的问题:假设这条规则,我想知道实际上可以重新排序什么指令。

“动作”定义如下:

Java 内存模型是根据操作指定的,包括对变量的读取和写入、监视器的锁定和解锁以及启动和加入线程。JMM 定义了一个偏序,称为发生在程序中的所有操作之前。为了保证执行action B的线程可以看到action A的结果(无论A和B是否发生在不同的线程中),A和B之间必须有happens before关系。在没有ahappens before ordering的情况下,两个之间的排序操作时,JVM 可以随意对它们进行重新排序。

其他提到的订单规则是:

  • 监控锁定规则。监视器锁上的解锁发生在同一监视器锁上的每个后续锁之前。
  • 易变的变量规则。对 volatile 字段的写入发生在对同一字段的每次后续读取之前。
  • 线程开始规则。对线程的 Thread.start 调用发生在已启动线程中的每个操作之前。
  • 线程终止规则。线程中的任何操作发生在任何其他线程检测到该线程已终止之前,要么通过从 Thread.join 成功返回,要么通过 Thread.isAlive 返回 false。
  • 中断规则。一个线程在另一个线程上调用中断发生在被中断的线程检测到中断之前(通过抛出 InterruptedException,或者调用 isInterrupted 或中断)。
  • 终结器规则。对象的构造函数的结束发生在该对象的终结器开始之前。
  • 传递性。如果 A 发生在 B 之前,B 发生在 C 之前,那么 A 发生在 C 之前。
0 投票
5 回答
4265 浏览

java - 如何使用 volatile 变量编写简单的线程安全类?

我想编写一个简单的线程安全类,可用于设置或获取 Integer 值。

最简单的方法是使用synchronized关键字:

我也可以尝试使用volatile

带有volatile关键字的类是线程安全的吗?

考虑以下事件序列:

  1. 线程 A 将值设置为 5。
  2. 线程 B 将值设置为 7。
  3. 线程 C 读取该值。

它遵循 Java 语言规范

  • “1”发生在“3”之前
  • “2”发生在“3”之前

但我看不出如何从规范中得出“1”发生在“2”之前,所以我怀疑“1”不会 发生在“2”之前。

我怀疑线程 C 可能读取 7 或 5。我认为带有volatile关键字的类不是线程安全的,以下顺序也是可能的:

  1. 线程 A 将值设置为 5。
  2. 线程 B 将值设置为 7。
  3. 线程 C 读取 7。
  4. 线程 D 读取 5。
  5. 线程 C 读取 7。
  6. 线程 D 读取 5。
  7. ...

我是否正确假设带有volatile的 MyIntegerHolder 不是线程安全的

是否可以通过使用 AtomicInteger 来制作线程安全的整数持有者:

?

这是 Java Concurrency In Practice 一书的片段:

原子变量的读取和写入与 volatile 变量具有相同的内存语义。

编写线程安全的MyIntegerHolder的最佳(最好是非阻塞)方法是什么?

如果你知道答案,我想知道你为什么认为它是正确的。它是否遵循规范?如果是这样,怎么做?

0 投票
4 回答
1641 浏览

java - 易失性读取发生在易失性写入之前吗?

我试图理解为什么这个例子是一个正确同步的程序:

因为存在冲突的访问(a 的写入和读取),所以在每个顺序一致性执行中,访问之间的关系必须先发生。假设顺序执行之一:

1 发生在 2 之前,为什么?

0 投票
1 回答
586 浏览

java - 是什么让不可变对象在没有安全发布技术的情况下发布?

即使不使用安全的发布习惯,也可以发布不可变对象是什么意思?

我已阅读实践中的 Java 并发第 3 章,共享对象),但仍然无法理解以下语句:

不可变对象可以通过任何机制发布。

应该安全地发布有效的不可变对象。

编辑:我已经通过关于 SO和答案的类似问题,但仍然无法理解如何安全地发布不可变对象,因为引用不可变对象的字段有可能被视为 null 或早期调用中的一些陈旧值通过外螺纹。

0 投票
1 回答
1929 浏览

java - 使用 volatile 和 synchronized 时,内存刷新或发布到各个线程的范围是什么?

这个问题仅涉及内存可见性,而不是发生在之前和之后。Java中有四种方法可以保证一个线程中对内存的更改对另一个线程可见。(参考http://gee.cs.oswego.edu/dl/cpj/jmm.html

  1. 写入线程释放同步锁,读取线程随后获取相同的同步锁。
  2. 如果一个字段被声明为易失性,则写入它的任何值都会在写入线程执行任何进一步的内存操作之前被写入线程刷新并使其可见(即,出于手头的目的,它会立即刷新)。
  3. 线程第一次访问对象的字段时,它会看到该字段的初始值或自其他线程写入以来的值。
  4. 当线程终止时,所有写入的变量都被刷新到主内存。

根据Java Concurrency in Practice,有关此类问题的圣经:

volatile 变量的可见性影响超出了 volatile 变量本身的值。当线程A写入 volatile 变量并且随后线程B读取相同的变量时,在写入 volatile 变量之前对A可见的所有变量的值在读取 volatile 变量后对B可见。

不稳定的问题

这是否意味着 JVM 实际上会跟踪 volatile 变量的读取和写入,以便知道如何将内存从A刷新到B而不是AC?所以A写入变量,然后C从变量中读取,然后B从变量中读取,刷新是在AB以及AC之间按线程完成的,但不是 BC?或者,这是否意味着所有缓存的内存都被刷新,而不管线程如何?是仅刷新 volatile 变量,还是所有缓存内存?

同步问题

对于synchronized关键字flushing,它表示只有在锁内更新的内存才能保证发布到其他线程。这意味着在下面的代码中,两个线程运行method(),离开同步块将刷新staticVar2到另一个线程,但不是 staticVar1,对吗?

此外,在 中method2(),如果另一个线程正在执行,则同步结束differentLock可能会导致发生前发生后发生问题method()。但是,问题在于可见性。如果线程A执行method,然后线程B稍后执行,即使两个线程没有在同一个锁上同步,method2()值是staticVar2A发布到B吗?

静态问题

在我看来,如果staticVar1从未更新到其他线程,那么任何程序中的所有静态变量都需要volatile声明,或者只能在synchronized块中访问。这似乎相当苛刻,但它是正确的吗?我确实在我的时间里看到了很多不同步的静态变量。

总之

  1. 易失性读写是否将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论答案是什么,是所有内存都被刷新还是只有 volatile 变量?
  2. 退出同步块时是否会刷新所有更改的内存,还是仅刷新块内更改的内存?如果不是所有内存都被刷新,线程同步的锁对象是否必须相同才能看到值(即锁对象对内存可见性有任何影响)?
  3. 两个线程访问的所有静态变量都必须同步吗?
0 投票
3 回答
358 浏览

java - Java新内存模型中的happens-before是否也适用于声明为易失性的对象的成员?

在新的 Java 内存模型中,对变量的任何写入都保证在下一个线程读取它之前完成。

我想知道作为该对象成员的变量是否也是这种情况。

对于java内存模型:

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

例如

和上面的代码一样,即使设置了functionMapvolatile,也不能保证函数对象在这个方法返回之前就已经完全构造好了。

我的想法对吗?

也只是为了这个话题,我想让你们检查一下我的想法是否适合以下内容:

像下面的任何写入functionMap保证在更改引用之前完成functionMap,对吧?无论initializeMap方法需要多长时间,其他线程要么看到 null 要么看到functionMap完全初始化的functionMap

上面澄清一下,上面两个例子都是在多线程环境下,functionMap变量会被多线程访问。