方法一:饿汉式:
package com.example.multithread.singleton;
import java.util.stream.IntStream;
/**
* 饿汉式:1.优点:类加载时就自动创建对象,禁止用户创建对象,天然线程安全,
* 2.缺点:类加载时jvm会创建静态对象实例,不管后续是否使用到该实例,造成内存浪费。
*/
public class HungerSafeSingleton {
//定义私有实例
private static HungerSafeSingleton instance = new HungerSafeSingleton();
//私有化构造,禁止调用者创建实例
private HungerSafeSingleton() {
}
//提供公开方法获取实例的静态方法
public static HungerSafeSingleton getInstance(){
return instance;
}
public static void main(String[] args) {
IntStream.rangeClosed(1,10).forEach(i->new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+HungerSafeSingleton.getInstance());
}
}.start());
}
}
方法二:懒汉式+双重检测
package com.example.multithread.singleton;
import java.util.stream.IntStream;
/**
* 懒汉式:1.优点:按需延迟加载实例化对象,节约内存空间,线程安全。
* 2.缺点:当实例对象引用了很多复杂对象时,调用单例实例的属性时,可能会抛空指针。
*/
public class LazyLoadSafeSingleton {
//定义私有实例
private static LazyLoadSafeSingleton instance;
//加volatile修饰
// private static volatile LazyLoadSafeSingleton instance;
//私有化构造,禁止调用者创建实例
private LazyLoadSafeSingleton() {
}
//1.引用了一些复杂的属性,
//2.new SafeSingleton2执行后,堆内存中就申请到了一片内存生成一个对象instance,这时满足 instance != null;
//3.但是这时由于延迟加载,jvm的优化,指令重排序等原因,复杂对象属性可能还未初始化完毕;
//4.这时instance.obj属性可能还是为null。
//5.解决方法就是加volatile,禁止jvm优化,只有所有属性都初始化完毕后才能调用对象实例。
private Object obj1;
private Object obj2;
private Object obj3;
public LazyLoadSafeSingleton(Object obj1, Object obj2, Object obj3) {
this.obj1 = obj1;
this.obj2 = obj2;
this.obj3 = obj3;
}
//提供公开方法获取实例的静态方法
// public static synchronized LazyLoadSafeSingleton getInstance(){
public static LazyLoadSafeSingleton getInstance(){
//双重检测
if(null == instance){
synchronized (LazyLoadSafeSingleton.class){
//如果这里没有再次判断,可能会出现一个线程执行到外层if后让出cpu执行权,
//另一个线程直接就把instance创建好了,导致创建了多个实例
if(null == instance){
instance = new LazyLoadSafeSingleton();
}
}
}
return instance;
}
public static void main(String[] args) {
IntStream.rangeClosed(1,10).forEach(i->new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+LazyLoadSafeSingleton.getInstance());
}
}.start());
}
}
方式三:内部静态类holder方式
package com.example.multithread.singleton;
import java.util.stream.IntStream;
/**
* 使用静态内部类holder方式:
* 1.优点:延迟加载,无需加锁,线程安全。
*
*/
public class HolderSafeSingleton {
//私有化构造,禁止调用者创建实例
private HolderSafeSingleton() {
}
//提供公开获取实例的静态
public static HolderSafeSingleton getInstance(){
return HolderSafeSingleton.StaticInstanceHolder.instance;
}
//静态内部类不会随着jvm加载类时创建实例,只有在调用时才会创建实例,满足了延迟加载
//非静态类,可以直接调用静态内部类
private static class StaticInstanceHolder{
private static HolderSafeSingleton instance = new HolderSafeSingleton();
}
public static void main(String[] args) {
IntStream.rangeClosed(1,10).forEach(i->new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+HolderSafeSingleton.getInstance());
}
}.start());
//Class<HolderSafeSingleton> c = HolderSafeSingleton.class;
// Constructor<HolderSafeSingleton> constructor = HolderSafeSingleton.class.getDeclaredConstructor();
//constructor.setAccessible(true);
//HolderSafeSingleton holderSafeSingleton = constructor.newInstance();
//System.out.println("reflect = "+holderSafeSingleton);
}
}
方式四:内部枚举方式
在这里插入代码片package com.example.multithread.singleton;
import java.util.stream.IntStream;
/**
* 内部枚举类方式,
* 优点:1.线程安全,延迟加载
*
*/
public class EnumSafeSingleton {
//私有化构造
private EnumSafeSingleton(){}
//公开获取实例对象静态方法
public static EnumSafeSingleton getInstance(){
return EnumSingleton.INSTANCES.getInstance();
}
//私有化的内部枚举类
//1.非静态类只有在调用时才会生成实例对象,满足延迟加载条件
//2.枚举类对象只会被创建一次,满足单例
private enum EnumSingleton{
INSTANCES;
private final EnumSafeSingleton instance;
private EnumSingleton(){
instance= new EnumSafeSingleton();
}
private EnumSafeSingleton getInstance(){
return instance;
}
}
public static void main(String[] args) {
IntStream.rangeClosed(1,10).forEach(i->new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+EnumSafeSingleton.getInstance());
}
}.start());
}
}