Skip to content

Commit 170d066

Browse files
feat
1 parent 6ad56ea commit 170d066

File tree

3 files changed

+156
-2
lines changed

3 files changed

+156
-2
lines changed

.gitignore

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,87 @@
1-
/out/
2-
.idea\
1+
.idea
2+
### Maven template
3+
target/
4+
pom.xml.tag
5+
pom.xml.releaseBackup
6+
pom.xml.versionsBackup
7+
pom.xml.next
8+
release.properties
9+
dependency-reduced-pom.xml
10+
buildNumber.properties
11+
.mvn/timing.properties
12+
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
13+
.mvn/wrapper/maven-wrapper.jar
14+
15+
### JetBrains template
16+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
17+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
18+
19+
# User-specific stuff
20+
.idea/**/workspace.xml
21+
.idea/**/tasks.xml
22+
.idea/**/usage.statistics.xml
23+
.idea/**/dictionaries
24+
.idea/**/shelf
25+
26+
# Generated files
27+
.idea/**/contentModel.xml
28+
29+
# Sensitive or high-churn files
30+
.idea/**/dataSources/
31+
.idea/**/dataSources.ids
32+
.idea/**/dataSources.local.xml
33+
.idea/**/sqlDataSources.xml
34+
.idea/**/dynamic.xml
35+
.idea/**/uiDesigner.xml
36+
.idea/**/dbnavigator.xml
37+
38+
# Gradle
39+
.idea/**/gradle.xml
40+
.idea/**/libraries
41+
42+
# Gradle and Maven with auto-import
43+
# When using Gradle or Maven with auto-import, you should exclude module files,
44+
# since they will be recreated, and may cause churn. Uncomment if using
45+
# auto-import.
46+
# .idea/artifacts
47+
# .idea/compiler.xml
48+
# .idea/jarRepositories.xml
49+
# .idea/modules.xml
50+
# .idea/*.iml
51+
# .idea/modules
52+
# *.iml
53+
# *.ipr
54+
55+
# CMake
56+
cmake-build-*/
57+
58+
# Mongo Explorer plugin
59+
.idea/**/mongoSettings.xml
60+
61+
# File-based project format
62+
*.iws
63+
64+
# IntelliJ
65+
out/
66+
67+
# mpeltonen/sbt-idea plugin
68+
.idea_modules/
69+
70+
# JIRA plugin
71+
atlassian-ide-plugin.xml
72+
73+
# Cursive Clojure plugin
74+
.idea/replstate.xml
75+
76+
# Crashlytics plugin (for Android Studio and IntelliJ)
77+
com_crashlytics_export_strings.xml
78+
crashlytics.properties
79+
crashlytics-build.properties
80+
fabric.properties
81+
82+
# Editor-based Rest Client
83+
.idea/httpRequests
84+
85+
# Android studio 3.1+ serialized cache file
86+
.idea/caches/build_file_checksums.ser
87+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package singleton.lazyman;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Set;
7+
import java.util.concurrent.*;
8+
9+
/**
10+
* @Author: zzStar
11+
* @Date: 12-08-2021 14:03
12+
*/
13+
public class Singleton {
14+
15+
private static Singleton singleton = null;
16+
17+
private Integer x = 1;
18+
19+
public static Singleton getInstance() {
20+
if (singleton == null) {
21+
synchronized (Singleton.class) {
22+
if (singleton == null) {
23+
singleton = new Singleton();
24+
}
25+
}
26+
}
27+
return singleton;
28+
}
29+
30+
private static void removeInstance() {
31+
singleton = null;
32+
}
33+
34+
public static void main(String[] args) throws InterruptedException, ExecutionException {
35+
ExecutorService pool = Executors.newCachedThreadPool();
36+
// 500个线程并发,执行1000_000次
37+
CyclicBarrier barrier = new CyclicBarrier(500);
38+
for (int i = 0; i < 1000_000; i++) {
39+
barrier.reset();
40+
System.out.println("i = " + i);
41+
List<Callable<Singleton>> list = new ArrayList<>();
42+
for (int j = 0; j < 500; j++) {
43+
list.add(() -> {
44+
barrier.await();
45+
Singleton instance = Singleton.getInstance();
46+
if (instance.x == null) {
47+
throw new RuntimeException("拿到了未被初始化的对象");
48+
}
49+
return instance;
50+
});
51+
}
52+
List<Future<Singleton>> futures = pool.invokeAll(list);
53+
Set<Singleton> set = new HashSet<>();
54+
for (Future<Singleton> future : futures) {
55+
set.add(future.get());
56+
}
57+
if (set.size() > 1) {
58+
System.out.println("并发生成多实例");
59+
throw new RuntimeException();
60+
}
61+
Singleton.removeInstance();
62+
}
63+
System.out.println("正常结束");
64+
}
65+
66+
}

JMM/src/singleton/lazyman/SingletonDoubleCheck.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
public class SingletonDoubleCheck {
1111

1212
// 新建对象中的三个步骤,重排序会带来的NPE,防止重排序
13+
// NPE: 由于重排序,可能会有线程获取到成员未初始化好的对象
14+
// new不是JVM原子指令,初始化与变量的引用绑定存储地址可能乱序,导致并发下会获取未初始化实例
1315
private volatile static SingletonDoubleCheck instance;
1416

1517
private SingletonDoubleCheck() {
@@ -18,6 +20,7 @@ private SingletonDoubleCheck() {
1820
public static SingletonDoubleCheck getInstance() {
1921

2022
if (instance == null) {
23+
// 锁instance本身会出现空指针
2124
synchronized (SingletonDoubleCheck.class) {
2225
// 第二个线程进来做一个判断检查,依然是空,才创建实例
2326
if (instance == null) {

0 commit comments

Comments
 (0)