单例模式与多线程

一、加载模式

1.1立即加载/饿汉模式

立即加载就是实用类的时候已经将对象创建完毕。常见的实现办法就是直接new实例化。
Myobject类:

public class Myobject {
    public static Myobject myobject = new Myobject();
    private Myobject(){

    }
    public static Myobject getInstance(){
        return myobject;
    }
}

myThread类:

public class myThread extends Thread {
    @Override
    public void run() {
        System.out.println(Myobject.getInstance().hashCode());
    }
}

test类:


public class test {
    public static void main(String[] args) {
        myThread my = new myThread();
        myThread my1 = new myThread();
        myThread my2 = new myThread();
        my.start();
        my1.start();
        my2.start();
    }
}

1.2 延迟加载/懒汉模式

延迟加载就是在调用get方法时实例才被创建,常见的实现方法就是get()方法中进行new实例化。

public class Myobject {
    public static Myobject myobject;

    private Myobject() {

    }

    public static Myobject getInstance() {
        if (myobject != null) {
        } else {
            myobject = new Myobject();
        }
        return myobject;
    }
}

1.3 延迟加载的缺点

在多线程的环境中,上述的实例代码完全就是错误的根本不能实现保持单例的状态。

public class test {
    public static void main(String[] args) {
        myThread my = new myThread();
        myThread my1 = new myThread();
        myThread my2 = new myThread();
        my.start();
        my1.start();
        my2.start();
    }
}

结果:

1201841772
499131126
499131126

1. 4 延迟加载的解决方案

  • 使用synchronzied关键字
    缺点:这种方法的运行效率特别低下,是同步运行的,必须等到上一个线程运行结束,才可以继续执行。
public static synchronized Myobject getInstance() {
        if (myobject != null) {
        } else {
            try {
                Thread.sleep(3000);
                myobject = new Myobject();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return myobject;
    }
  • 使用同步代码块
    同样方法的运行效率低下
public class Myobject {
    public static Myobject myobject;

    private Myobject() {

    }

    public static Myobject getInstance() {
        synchronized (Myobject.class) {
            if (myobject != null) {
            } else {
                try {
                    Thread.sleep(3000);
                    myobject = new Myobject();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return myobject;
        }
    }
  • 针对某些重要的代码进行单独的同步
    虽然部分代码上锁,但还是有非线程安全问题,不过方法运行次效率提高了很多。
public static Myobject getInstance() {
            if (myobject != null) {
            } else {
                try {
                    Thread.sleep(3000);
                    synchronized (Myobject.class) {
                        myobject = new Myobject();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return myobject;
        }
  • 使用DCL双检查锁机制
    实现多线程环境中延迟加载单例设计模式
    同步代码块里再加一次判断为空的情况,与前面的判断非空构成双检查锁。
    public static Myobject getInstance() {
            if (myobject != null) {
            } else {
                try {
                    Thread.sleep(3000);
                    synchronized (Myobject.class) {
                        if(myobject == null)
                        myobject = new Myobject();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return myobject;
        }

二、其他方法实现

2.1 使用静态内之类实现单例模式

public class Myobject {
    private static class inObject {
        private static Myobject my = new Myobject();
    }

    private Myobject() {

    }

    public static Myobject getInstance() {
        return inObject.my;
    }
}

结果:

376599429
376599429
376599429

2.2 序列化与反序列化的单例模式的实现

静态内置类可以达到线程安全问题,但如果遇到序列化现象时,使用默认的方式得到的结果还是多例的。
主方法:

public class test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Myobject instance = Myobject.getInstance();
        FileOutputStream fileOutputStream = new FileOutputStream(new File("myObjectFile.txt"));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        fileOutputStream.close();
        objectOutputStream.close();
        System.out.println(instance.hashCode());
        FileInputStream fileInputStream = new FileInputStream(new File("myObjectFile.txt"));
        ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
        Myobject myobject = (Myobject) inputStream.readObject();
        fileInputStream.close();
        inputStream.close();
        System.out.println(myobject.hashCode());
    }
}

使用序列化:

public class Myobject implements Serializable {
    private static  final long serialVersionUID = 888l;
    private static class inObject {
        private static Myobject my = new Myobject();
    }

    private Myobject() {

    }

    public static Myobject getInstance() {
        return inObject.my;
    }
}

结果:

2001049719
396180261
  • 解决方法:
    加入这个方法:
 protected Object readResolve(){
        System.out.println("调用了一个特殊的方法");
        return inObject.my;
    }

2.3 使用static代码块实现单例模式


public class Myobject implements Serializable {
    private static  Myobject myobject = null;
     static {
        myobject = new Myobject();
    }
    private Myobject() {
    }
    public static Myobject getInstance() {
        return myobject;
    }
}

2.4 使用枚举数据类型实现单例模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值