java设计模式之1单例模式

1. 单例模式

不能new产生新的对象,只能获取一个对象。
分为懒汉式和饿汉式。
饿汉式: 不管是否需要创建对象,都会new一个对象出来。
懒汉式:等创建对象的时候,才会new,

单例模式实现步骤

1.私有化构造器(这样就不能new了)

2.构造一个共有方法 获得这个类的对象

饿汉单例模式


/**
 * @Description 恶汉模式
 * @Author java川
 * @Date 2021-04-28-12:39
 */


//缺点是浪费内存
public class Hungry {

    private static final Hungry hungry=new Hungry ();//无论是否创建该Hungry对象 都生成一个对象
    private Hungry()
    {

    }  //私有化构造器  不能new

    public static  Hungry getInstance(){
        return hungry;
    }
}


懒汉单例模式(多线程不安全):

/**
 * @Description
 * @Author java川
 * @Date 2021-04-28-13:31
 */
public class LazyManNoSafe {
    private static LazyManNoSafe lazyManNoSafe = null;

    //私有化构造器
    private LazyManNoSafe() {
        System.out.println (Thread.currentThread ().getName () + "OK");
    }

    //公开的获得实例化对象的方法
    public static LazyManNoSafe getInstance() {
        if (lazyManNoSafe == null) {
            lazyManNoSafe = new LazyManNoSafe ();
        }
        return lazyManNoSafe;
    }


    public static void main(String[] args) {
        //创建10个线程实例化对象
        for (int i = 0; i < 10; i++) {
            new Thread (){
                @Override
                public void run() {
                    LazyManNoSafe.getInstance ();
                }
            }.start ();
        }

    }
}

但是懒汉单例模式有一个问题是:
getInsance方法创建对象时,
lazyManNoSafe = new LazyManNoSafe (); 这一步操作new不是线程安全的,并且多线程环境调用getinstabce没有加锁,也导致线程不安全,会创建多个对象。

会创建多个对象(不一定是以下6个)
在这里插入图片描述

new分为三个步骤

1.分配内存
2.执行构造方法实例化对象
3.对象地址指向内存地址。

如果线程A分配内存了,但是线程A跳过2步骤,直接对象地址指向内存地址,此时内存中是没有该对象的,线程B去调用getInance方法,就会直接返回该对象(但该对象线程A并没有初始化)。

所以我们需要保证线程安全,保证调用getInance方法的时候是一个线程在执行,同时使得new对象原子化。

多线程安全版DCL 懒汉式单例模式:

/**
 * @Description 懒汉方式  缺点是只适合单线程 多线程的话就会创建多个
 * @Author java川
 * @Date 2021-04-28-12:44
 */

public class LazyMan {
    private static volatile LazyMan lazyman=null;//volatitle保证原子性操作

    //私有化构造器
    private LazyMan(){
        System.out.println (Thread.currentThread ().getName ()+"OK");

    }

    //公开的获得实例化对象的方法
    public  static  LazyMan getInstance(){
        if(lazyman==null){
           synchronized (LazyMan.class){   //双重机制 加锁  防止多线程进来对象还未初始化 就进来了。
               if(lazyman==null){
                   lazyman=new LazyMan ();//线程不安全
                   /*
                   1.分配内存空间
                   2.执行构造方法初始化对象
                   3.将对象地址指向内存空间地址。
                    */
               }
           }
        }
        return lazyman;

    }
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread (new Runnable () {
                public void run() {
                    LazyMan.getInstance ();
                }
            }).start ();
        }
    }
}

2.volatile关键字

volatile关键字保证了操作的原子性。

原子性:就是一个操作,不可分割。

volatile如何保证原子性的呢?

java的工作模式,多线程环境中每个线程都有一个独立的工作栈,还有一个主存,是公共区间。
每个线程从主存中读取共有变量,放到自己的工作栈中处理,但并不立刻写回主存,所以其他线程从主存中读取的数据并不是最新数据,就会导致线程不安全。

volatile关键字的作用就是将处理好的变量立刻写回主存,方便其他线程从主存中读取到最新数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值