單例模式分爲兩大種,一種是餓漢模式,一種是懶漢模式(懶加載)
餓漢模式
1.單例-餓漢模式 佔用內存常駐,靜態常量直接初始化
public class Singleton01 {
//單例-餓漢模式 佔用內存常駐
private Singleton01() {
if(SINGLETON!=null){
throw new RuntimeException();
}
}
private static final Singleton01 SINGLETON = new Singleton01();
public Singleton01 getInstance() {
return SINGLETON;
}
}
2.單例-餓漢模式 不佔用內存常駐,採用靜態內部類直接初始化
public class Singleton02 {
//單例-餓漢模式 不佔用內存常駐
private static class Singleton02Inner {
private static final Singleton02 SINGLETON = new Singleton02();
}
private Singleton02() {
if (Singleton02Inner.SINGLETON != null) {
throw new RuntimeException();
}
}
public Singleton02 getInstance() {
return Singleton02Inner.SINGLETON;
}
3.採用枚舉類型
public enum Singleton03 {
//枚舉實例
SINGLETON;
public void otherMethod() {
}
}
懶漢模式(懶加載)
4.單例-懶漢模式 實現懶加載,線程不安全,多線程時,不一定只有一個實例
public class Singleton04 {
//單例-懶漢模式 實現懶加載,線程不安全
private static Singleton04 singleton = null;
private Singleton04() {
if (singleton != null) {
throw new RuntimeException();
}
}
public static Singleton04 getInstance() {
if (singleton == null) {
singleton = new Singleton04();
}
return singleton;
}
public static void main(String[] args) {
System.out.println(getInstance() == getInstance());
}
}
5.單例-懶漢模式 線程安全寫法,但是效率不高,開銷大
public class Singleton05 {
//單例-懶漢模式 線程安全寫法,但是效率不高,開銷大
private static Singleton05 singleton = null;
private Singleton05() {
if (singleton != null) {
throw new RuntimeException();
}
}
public static synchronized Singleton05 getInstance() {
if (singleton == null) {
singleton = new Singleton05();
}
return singleton;
}
public static void main(String[] args) {
System.out.println(getInstance() == getInstance());
}
}
6.單例-懶漢模式 線程不完全安全寫法,效率比同步方法高,雙重校驗鎖
public class Singleton06 {
//單例-懶漢模式 線程不完全安全寫法,效率比同步方法高,雙重校驗鎖
private static Singleton06 singleton = null;
private Singleton06() {
if (singleton != null) {
throw new RuntimeException();
}
}
public static Singleton06 getInstance() {
if (singleton == null) {
synchronized (Singleton06.class) {
if (singleton == null) {
singleton = new Singleton06();
}
}
}
return singleton;
}
}
7.單例-懶漢模式 線程安全寫法,效率比同步方法高,雙重校驗鎖升級版
public class Singleton07 {
//單例-懶漢模式 線程安全寫法,效率比同步方法高,雙重校驗鎖升級版
//volatile 起到禁止指令重排的作用,在它賦值完成之前,就不會調用讀操作(singleton == null)。
private static volatile Singleton07 singleton = null;
private Singleton07() {
if (singleton != null) {
throw new RuntimeException();
}
}
public static Singleton07 getInstance() {
if (singleton == null) {
synchronized (Singleton07.class) {
if (singleton == null) {
singleton = new Singleton07();
}
}
}
return singleton;
}
}
8.使用 ThreadLocal 實現(線程安全)
public class Singleton08 {
//使用 ThreadLocal 實現(線程安全)
//ThreadLocal 會爲每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。
//對於多線程資源共享的問題,
// 同步機制採用了“以時間換空間”的方式,而ThreadLocal 採用了“以空間換時間”的方式。
// 前者僅提供一份變量,讓不同的線程排隊訪問,而後者爲每一個線程都提供了一份變量,
// 因此可以同時訪問而互不影響。
private static final ThreadLocal<Singleton08> SINGLETON = new ThreadLocal<Singleton08>() {
@Override
protected Singleton08 initialValue() {
return new Singleton08();
}
};
private Singleton08() {
}
public static Singleton08 getInstance() {
return SINGLETON.get();
}
}
9.CAS鎖實現,比較再交換(線程安全)
public class Singleton09 {
//CAS鎖實現,比較再交換
private static final AtomicReference<Singleton09> SINGLETON = new AtomicReference<>();
private Singleton09() {
}
public static final Singleton09 getInstance() {
for (; ; ) {
Singleton09 current = SINGLETON.get();
if (current != null) {
return current;
}
current = new Singleton09();
if (SINGLETON.compareAndSet(null, current)) {
return current;
}
}
}
public static class MyTest {
@Test
public void test() throws InterruptedException {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 100000; i++) {
long i1 = i ^ 5;
System.out.println(i1);
}
System.out.println("aaaa");
notifyAll();
Thread.currentThread().sleep(10000);
System.out.println("fdsafsa");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
th.start();
th.join();
System.out.println("woshitest");
}
}
}