Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: add case instruction reordering causes non-final field variable #64

Merged
merged 4 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
- uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: zulu
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ Examples of concurrency problems you encountered in development are welcome to p
- [Demo description](#demo-description-7)
- [Problem statement](#problem-statement-7)
- [Quickly run](#quickly-run-7)
- [🍺 Instruction reordering causes non-final field variable read error](#-instruction-reordering-causes-non-final-field-variable-read-error)
- [Demo description](#demo-description-8)
- [Problem statement](#problem-statement-8)
- [Quickly run](#quickly-run-8)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -233,3 +237,23 @@ this is a livelock.
```bash
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.ReentrantLockLivelockDemo
```

## 🍺 Instruction reordering causes non-final field variable read error

Demo class [`FinalInitialDemo`](src/main/java/fucking/concurrency/demo/FinalInitialDemo.java).

### Demo description

The writer thread calls the constructor of the class, and the reader thread obtains the member variables of the non-final domain of the class.

### Problem statement

When calling the constructor, instruction reordering may occur, placing non-final domain variables outside the constructor,
causing the writer and reader threads to obtain the default initial values of the variables.(Instruction ordering does not necessarily occur
and requires specific hardware and JVM environments).

### Quickly run

```bash
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.FinalInitialDemo
```
23 changes: 23 additions & 0 deletions docs/zh-CN/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
- [Demo说明](#demo%E8%AF%B4%E6%98%8E-6)
- [问题说明](#%E9%97%AE%E9%A2%98%E8%AF%B4%E6%98%8E-6)
- [快速运行](#%E5%BF%AB%E9%80%9F%E8%BF%90%E8%A1%8C-6)
- [🍺 指令重排序导致非final域变量读取错误](#-指令重排序导致非final域变量读取错误)
- [Demo说明](#demo%E8%AF%B4%E6%98%8E-7)
- [问题说明](#%E9%97%AE%E9%A2%98%E8%AF%B4%E6%98%8E-7)
- [快速运行](#%E5%BF%AB%E9%80%9F%E8%BF%90%E8%A1%8C-7)
- [一些并发的问题讨论和资料](#%E4%B8%80%E4%BA%9B%E5%B9%B6%E5%8F%91%E7%9A%84%E9%97%AE%E9%A2%98%E8%AE%A8%E8%AE%BA%E5%92%8C%E8%B5%84%E6%96%99)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->
Expand Down Expand Up @@ -209,6 +213,25 @@ Demo类[`SymmetricLockDeadlockDemo`](../../src/main/java/fucking/concurrency/dem
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.SymmetricLockDeadlockDemo
```

## 🍺 指令重排序导致非final域变量读取错误

Demo类[`FinalInitialDemo`](../../src/main/java/fucking/concurrency/demo/FinalInitialDemo.java)。

### Demo说明

writer线程调用类的构造函数,reader线程获取类的非final的成员变量。

### 问题说明

调用构造函数时,可能会发生指令重新排序,将非final域变量放置在构造函数之外,导致writer和reader线程获取变量的默认初始值(指令顺序不一定发生,
并且需要特定的硬件和 JVM 环境)。

### 快速运行

```bash
./mvnw compile exec:java -Dexec.mainClass=fucking.concurrency.demo.FinalInitialDemo
```

## 一些并发的问题讨论和资料

- [ibm developerworks - 多核系统上的`Java`并发缺陷模式(`bug patterns`)](http://www.ibm.com/developerworks/cn/java/j-concurrencybugpatterns/)
Expand Down
16 changes: 8 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,35 +68,35 @@
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.2</version>
<version>3.6.3</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<version>3.2.5</version>
</plugin>
<plugin>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.1.0</version>
<version>3.2.4</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.1</version>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.1</version>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/fucking/concurrency/demo/FinalInitialDemo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package fucking.concurrency.demo;


/**
* @author hyy (hjlbupt at 163 dot com)
*/
public class FinalInitialDemo {

private int a;
private boolean flag;
private FinalInitialDemo demo;

public FinalInitialDemo() {
a = 1;
flag = true;
}

public void writer() {
demo = new FinalInitialDemo();
}

public void reader() {
if (flag) {
int i = a * a;
if (i == 0) {
// On my dev machine, the variable initial always success.
// To solve this problem, add final to the `a` field and `flag` field.
System.out.println("Fuck! instruction reordering occurred.");
}
}
}

@SuppressWarnings("InfiniteLoopStatement")
public static void main(String[] args) throws Exception {
while (true) {
FinalInitialDemo demo = new FinalInitialDemo();
Thread threadA = new Thread(demo::writer);
Thread threadB = new Thread(demo::reader);

threadA.start();
threadB.start();

threadA.join();
threadB.join();
}
}
}