02 Singleton单例

抽丝剥茧设计模式 之 Singleton单例 - 更多内容请见 目录


一、Singleton单例

Singleton单例常用于manager等只需要有一个实例的地方,但是由于正常情况我们无法阻止其他人创建实例,所以我们需要用Singleton单例模式来约束。
Singleton单例模式有8种写法,但是只有两种(7、8)完美无缺,但是完美的不常用。

二、单例模式的八种实现

1、饿汉式1

Java实现

/**
 * 饿汉式
 * 类加载到内存后,就实例化一个单例,JVM,保证线程安全,
 * 简单实用,推荐使用。
 * 唯一缺点,不管用到与否,类装载时就完成了实例化。
 */
  
public class Singleton {
    // 私有静态成员变量,直接创建实例
    private static final Singleton instance = new Singleton();

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static Singleton getInstance() {
        return instance;
    }
    
}

public class Main {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.hashCode());

        Singleton anotherSingleton = Singleton.getInstance();
        System.out.println(anotherSingleton.hashCode());

        // 输出结果应为相同的hashCode,表示只有一个实例被创建
    }
}


go实现

package main

import (
    "fmt"
    "sync"
)

// 饿汉式
type Singleton struct{}

// 私有静态成员变量,直接创建实例
var instance *Singleton = &Singleton{}
var once sync.Once

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}

2、饿汉式2

Java实现

/**
 * 饿汉式
 * 用静态语句块保证当getInstance()调用时才创建实例
 */


public class Singleton {
    // 私有静态成员变量,用静态语句块创建实例
    private static final Singleton instance;
    static {
        instance = new Singleton();
    }

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static Singleton getInstance() {
        return instance;
    }
    
}

public class Main {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.hashCode());

        Singleton anotherSingleton = Singleton.getInstance();
        System.out.println(anotherSingleton.hashCode());

        // 输出结果应为相同的hashCode,表示只有一个实例被创建
    }
}

go实现

package main

import (
    "fmt"
    "sync"
)

// 饿汉式
type Singleton struct{}

// 私有静态成员变量,直接创建实例
var instance *Singleton
var once sync.Once

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}

3、懒汉式

Java实现

/**
 * 懒汉式
 * 虽然达到了按需初始化的目的,但却带来了线程不安全的问题。
 */
  
public class Singleton {
    // 私有静态成员变量
    private static Singleton instance;

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static /*synchronized*/ Singleton getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Singleton();
        }
        return instance;
    }
    
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton singleton = Singleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " - " + singleton.hashCode());
            }).start();
        }
    }
}

go实现

package main

import (
    "fmt"
    "sync"
)

// 懒汉式
type Singleton struct{}

var instance *Singleton
var once sync.Once

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    if instance == nil {
        instance = &Singleton{}
    }
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
    wg := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singleton := GetInstance()
            fmt.Println(singleton.hash())
        }()
    }
    wg.Wait()
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}

4、懒汉式-加锁

Java实现

/**
 * 懒汉式
 * 虽然达到了按需初始化的目的,但却带来了线程不安全的问题。
 */
  
public class Singleton {
    // 私有静态成员变量
    private static Singleton instance;

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new Singleton();
        }
        return instance;
    }
    
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton singleton = Singleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " - " + singleton.hashCode());
            }).start();
        }
    }
}

go实现

package main

import (
    "fmt"
    "sync"
)

// 懒汉式
type Singleton struct{}

var instance *Singleton
var once sync.Once
var mu sync.Mutex

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    mu.Lock()
    defer mu.Unlock()

    if instance == nil {
        instance = &Singleton{}
    }
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
    wg := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singleton := GetInstance()
            fmt.Println(singleton.hash())
        }()
    }
    wg.Wait()
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}


5、懒汉式-缩小加锁代码块

Java实现

/**
 * 懒汉式
 * 虽然达到了按需初始化的目的,但却带来了线程不安全的问题。
 */
  
public class Singleton {
    // 私有静态成员变量
    private static Singleton instance;

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                instance = new Singleton();
            }
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton singleton = Singleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " - " + singleton.hashCode());
            }).start();
        }
    }
}


go实现

package main

import (
    "fmt"
    "sync"
)

// 懒汉式
type Singleton struct{}

var instance *Singleton
var once sync.Once
var mu sync.Mutex

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    if instance == nil {
        mu.Lock()
        instance = &Singleton{}
        mu.Unlock()
    }
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
    wg := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singleton := GetInstance()
            fmt.Println(singleton.hash())
        }()
    }
    wg.Wait()
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}

6、懒汉式-双判断

Java实现

/**
 * 懒汉式
 * 虽然达到了按需初始化的目的,但却带来了线程不安全的问题。
 */
  
public class Singleton {
    // 私有静态成员变量
    private static volatile Singleton instance;

    // 私有构造方法,防止外部实例化
    private Singleton() { }

    // 公有静态方法,获取实例
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
            	if (instance == null) {
            		try {
	                    Thread.sleep(1);
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                }
	                instance = new Singleton();
            	}
            }
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton singleton = Singleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " - " + singleton.hashCode());
            }).start();
        }
    }
}


go实现

package main

import (
    "fmt"
    "sync"
)

// 懒汉式
type Singleton struct{}

var instance *Singleton
var once sync.Once
var mu sync.Mutex

// 公有静态方法,获取实例
func GetInstance() *Singleton {
    if instance == nil {
        mu.Lock()
        if instance == nil {
        	instance = &Singleton{}
        }
        mu.Unlock()
    }
    return instance
}

func main() {
    singleton := GetInstance()
    fmt.Println(singleton.hash())

    anotherSingleton := GetInstance()
    fmt.Println(anotherSingleton.hash())

    // 输出结果应为相同的hashCode,表示只有一个实例被创建
    wg := sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singleton := GetInstance()
            fmt.Println(singleton.hash())
        }()
    }
    wg.Wait()
}

func (s *Singleton) hash() int {
    return int(uintptr(unsafe.Pointer(s)))
}

7、静态内部类-同时保证线程安全和懒加载

Java实现

/**
 * 靠JVM保证线程安全
 * 当外部类被加载时,内部类不会被加载
 * 当getInstance()被调用,SingletonHolder被加载
 * SingletonHolder是内部类,可以调用私有的构造器
 */
  
public class Singleton {
    // 私有构造方法,防止外部实例化
    private Singleton() { }

	private static class SingletonHolder {
		// 私有静态成员变量
    	private final static Singleton instance = new Singleton();
	}
	public static Singleton getInstance() {
		return SingletonHolder.instance;
	}
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Singleton singleton = Singleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " - " + singleton.hashCode());
            }).start();
        }
    }
}


8、枚举单例

Java实现

/**
 * 枚举单例,不仅解决线程同步,还可以防止反序列化
 */
public enum Singleton {
	instance;
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " - " + Singleton.instance.hashCode());
            }).start();
        }
    }
}



总结

老实用第一种就可以了。最后两种我没想好该怎么对应go的语法,容我想想。

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值