单例模式的各种写法和总结 懒汉式 饿汉式 登记式

public class Singleton {//懒汉式单例类
/**
 懒汉式单例类。   只在外部对象第一次请求实例的时候才会去创建
     优点:第一次调用时才会初始化,避免内存浪费。
    缺点:必须加锁synchronized 才能保证单例
 */
  private static volatile Singleton singleton;// !!必须要加volatile限制指令重排序,不然这是双重检验的漏洞
    private static final ReentrantLock lock = new ReentrantLock();
    private static AtomicInteger count=new AtomicInteger(0);
    private Singleton() {
        count.incrementAndGet();
    }

    public static synchronized  Singleton getInstance() {
    
        if (singleton == null) {
            lock.lock();
            if (singleton == null) { //双重锁定,防止几个线程同时进入,eg:a进入,bc等待,a第一次实例化单例,b得到锁后进入,
                                        //此处如不判断,则b也会实例化单例,造成多次实例化。 但是多线程测试中没出现这种情况
                singleton = new Singleton();
            }
            lock.unlock();
        }
        return singleton;
    }
    public void show(){
        System.out.println(count);
    }
    
    public static void main(String[] args) throws InterruptedException {
//        Singleton s1 = Singleton.getInstance();
//        Singleton s2 = Singleton.getInstance();
//        if (s1 == s2)
//            System.out.println("euqal");//equal
//        else {
//            System.out.println("not equal");
//        }
        
        ExecutorService service = Executors.newCachedThreadPool();
        for(int i=0;i<50;i++){
            Thread t =new Thread(new MyThread());
            service.execute(t);
        }

        Thread.sleep(5000);
        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        Singleton s = Singleton.getInstance();
        s.show();
    }
    
}

饿汉式单例类

public class SingletonHungry {
public static void main(String[] args) throws InterruptedException {
    ExecutorService service = Executors.newCachedThreadPool();
    for(int i=0;i<30;i++){
        Thread t =new Thread(new MyThread2());
        service.execute(t);
    }

    Thread.sleep(1000);
    service.shutdown();
}
}
/*
       饿汉式单例类。    它在类加载时就立即创建对象。
       优点:没有加锁,执行效率高。  用户体验上来说,比懒汉式要好。
        缺点:类加载时就初始化,浪费内存
 */
class Singleton2{
    private static AtomicInteger count = new AtomicInteger(10);
    private static final Singleton2 SINGLETON = new Singleton2();
    private Singleton2(){
        count.incrementAndGet();
    }
    public static Singleton2 getInstance(){
        return SINGLETON;
    }
    public void show() {
        System.out.println(count);
    }
}
class MyThread2 implements Runnable{

    @Override
    public void run() {
        Singleton2 s2 = Singleton2.getInstance();
        s2.show();
    }
    
}

登记式模式

内部类只有在外部类被调用才加载,产生SINGLETON实例,又不用加锁,此模式有上述俩模式的优点,屏蔽了他们的缺点,是最好的单例模式。
public class Singleton{
    private Singleton(){}
    public static Singleton getInstance(){ return Holder.SINGLETON;}
    private static class Holder{//内部类
        private static final Singleton SINGLETON= new Singleton();
    }
}
单例类的特点:
1、单例类确保自己只有一个实例
2、单例类必须自己创建自己的实例
3、单例类必须为其他对象提供唯一的实例。

单例类的优点:

(1) 控制资源的使用,通过线程同步来控制资源的并发访问。
(2)控制实例的产生数量,达到节约资源的目的。
(3)作为通信的媒介,数据共享。他可以在不建立直接关联的条件下,让多个不相关的两个线程或者多个进程之间实现通信。

单例类实用举例:Windows的任务管理器,打不开两个。 网站的计数器,不然很难实现同步。   数据库连接池的设计

原文地址:https://www.cnblogs.com/todayjust/p/5810202.html