下文是筆者編寫的單例模式實作的八種方式,如下所示:
單例模式的簡介
我們将一個類在目前程序中隻有一個執行個體的這種模式,稱之為“單例模式”
那麼Java代碼如何實作一個單例模式呢?下文将一一到來,如下所示:
單例模式的注意事項:
1.單例模式在一個程序中隻有一個執行個體
2.單例類通常由自己建立自身的執行個體
3.單例類給其他對象提供的都是同一個執行個體
測試代碼
package com.java265.Singleton;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("------單例模式-----");
//建立100個線程進行測試
for(int i=0;i<100;i++) {
new Thread(()->{
System.out.println(Single01.getInstance());
}).start();
}
}
}
單例實作模式1
餓漢式單例模式:
直接使用一個靜态變量,在JVM加載類時,生成一個單例執行個體
如下
package com.java265.Singleton;
public class Single01 {
private static final Single01 INSTANCE = new Single01();
private Single01() {}
public static Single01 getInstance () {
return INSTANCE;
}
}
使用static靜态代碼塊生成一個單例類
package com.java265.Singleton;
public class Single02 {
private static final Single02 INSTANCE;
static {
INSTANCE = new Single02();
}
private Single02() {}
public static Single02 getInstance() {
return INSTANCE;
}
public void t() {
System.out.println("Single02 t方法"
+ "");
}
}
使用判斷的方式,建立單例模式,
但是此處不是一個線程安全的建立方式
package com.java265.Singleton;
/*
* 這是一個線程不安全的建立單例模式的方式
* 這是一個懶漢式的建立單例模式的方式
* */
public class Single03 {
private static Single03 INSTANCE;
private Single03() {
}
public static Single03 getInstance() {
if(INSTANCE ==null)
{
// 多個線程都會被卡在此處,
// 當sleep運作完畢後,多個線程會同時建立執行個體,此處的代碼是産生線程不安全的根源
try
{
Thread.sleep(100);
}catch(InterruptedException e)
{
}
INSTANCE = new Single03();
}
return INSTANCE;
}
}
使用 synchronized為方法加上鎖,使其線程安全
package com.java265.Singleton;
public class Single04 {
private static volatile Single04 INSTANCE;
private Single04() {
}
/*
* 懶漢式生成單例執行個體 此處使用 synchronized 安全鎖
*/
public static synchronized Single04 getInstance() {
if(INSTANCE ==null)
{
try
{
Thread.sleep(100);
}catch(InterruptedException e)
{
}
INSTANCE = new Single04();
}
return INSTANCE;
}
}
減少鎖粒度,将synchronized關鍵字直接加在方法内部具體的位置上
package com.java265.Singleton;
public class Single05 {
private static Single05 INSTANCE;
private Single05() {
}
public static Single05 getInstance() {
if(INSTANCE ==null)
{
/*
* 将鎖直接加到方法體裡面 此時出現了一個新的問題 當所有的線程都堵塞在此處,也會建立多個執行個體
*/
synchronized(Single05.class) {
try
{
Thread.sleep(100);
}catch(InterruptedException e)
{
}
INSTANCE = new Single05();
}
}
return INSTANCE;
}
}
将synchronized鎖放入在方法體中,同時使用雙重檢查,避免建立多個執行個體
package com.java265.Singleton;
public class Single06 {
private static Single06 INSTANCE;
private Single06() {
}
public static Single06 getInstance() {
if(INSTANCE ==null)
{
synchronized(Single06.class) {
try
{
Thread.sleep(100);
}catch(InterruptedException e)
{
}
if(INSTANCE == null)
{
INSTANCE = new Single06();
}
}
}
return INSTANCE;
}
}
使用靜态内部類的方式建立一個單例對象
此方式主要借助JVM加載類時,内部類不會被加載
當我們使用内部類的時,才會被加載,此時由JVM保證靜态内部類的唯一性
package com.java265.Singleton;
/*
* 采用内部類的方式實作一個單例模式
* */
public class Single07 {
private Single07() {
}
private static class Single07Holder {
private final static Single07 INSTANCE = new Single07();
}
public static Single07 getInstance() {
return Single07Holder.INSTANCE;
}
}
使用枚舉建立一個靜态内部類
package com.java265.Singleton;
/*
* 采用枚舉實作一個單例模式
* */
public enum Single08 {
INSTANCE;
public static Single08 getInstance() {
return INSTANCE;
}
}