Java多线程学习六 多线程下的单例模式

一、饿汉模式

public class MyObject {
    //饿汉模式
    private static MyObject myObject=new MyObject();
    private MyObject(){

    }
    public static MyObject getInstance(){
        return myObject;
    }
}
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
    public static void main(String[] args) {
        MyThread myThread1=new MyThread();
        MyThread myThread2=new MyThread();
        MyThread myThread3=new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
343451155
343451155
343451155

没毛病老铁

二、懒汉

public class MyObject {
    private static MyObject myObject;
    private MyObject(){

    }
    public static MyObject getInstance(){
        //懒汉模式
        if (myObject==null){
            try {
                //模拟创建对象前做的准备工作
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myObject=new MyObject();
        }
        return myObject;
    }
}
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class TestMain {
    public static void main(String[] args) {
        MyThread myThread1=new MyThread();
        MyThread myThread2=new MyThread();
        MyThread myThread3=new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}
1875573029
961745937
1312341120

有毛病老铁

三、线程安全问题解决方案

  1. 在getInstence方法前加synchronized
    整个方法被上锁,效率太低
  2. DCL双检查锁机制
public class MyObject {
    private static MyObject myObject;
    private MyObject(){

    }
    public static synchronized MyObject getInstance(){
        //懒汉模式
        if (myObject==null){
            try {
                Thread.sleep(1000);
                //把准备工作排开
                synchronized (MyObject.class){
                    if (myObject==null){
                        myObject=new MyObject();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return myObject;
    }
}

这样既保证了效率又保证了安全。

四、单例模式与序列化的爱恨情仇

public class MyObject implements Serializable {
    private static final long serialVersionUID=1L;
    //内部类方式
    private static class MyObjectHandler{
        private static final MyObject myObject=new MyObject();
    }
    private MyObject(){
    }
    public static MyObject getInstance(){
        return MyObjectHandler.myObject;
    }

//    protected Object readResolve() throws ObjectStreamException{
//        System.out.println("调用了readResolve方法!");
//        return MyObjectHandler.myObject;
//    }
}

public class TestMain {
    public static void main(String[] args) {
       writeObject();
       readObject();
    }

    public static void writeObject(){
        FileOutputStream fileOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            MyObject myObject = MyObject.getInstance();
            System.out.println(myObject.hashCode());
            fileOutputStream = new FileOutputStream(new File("E:/a.txt"));
            objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(myObject);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void readObject(){
        FileInputStream fileInputStream=null;
        ObjectInputStream objectInputStream=null;
        try {
            fileInputStream=new FileInputStream(new File("E:/a.txt"));
            objectInputStream=new ObjectInputStream(fileInputStream);
            MyObject myObject= (MyObject) objectInputStream.readObject();
            System.out.println(myObject.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if (objectInputStream!=null){
                    objectInputStream.close();
                }
                if (fileInputStream!=null){
                    fileInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

单例模式序列化后再反序列化读进来的和写入的已经不是同一个对象了,解决方法就是把注释掉的代码放开
这个方法是基于回调的,反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要在创建新的对象!

你可能感兴趣的:(Java多线程学习六 多线程下的单例模式)