Java多線程學(xué)習(xí)六 多線程下的單例模式

一、餓漢模式

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 {
                //模擬創(chuàng)建對(duì)象前做的準(zhǔn)備工作
                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
    整個(gè)方法被上鎖,效率太低
  2. DCL雙檢查鎖機(jī)制
public class MyObject {
    private static MyObject myObject;
    private MyObject(){

    }
    public static synchronized MyObject getInstance(){
        //懶漢模式
        if (myObject==null){
            try {
                Thread.sleep(1000);
                //把準(zhǔn)備工作排開
                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;
    //內(nèi)部類方式
    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("調(diào)用了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();
            }
        }
    }
}

單例模式序列化后再反序列化讀進(jìn)來的和寫入的已經(jīng)不是同一個(gè)對(duì)象了,解決方法就是把注釋掉的代碼放開
這個(gè)方法是基于回調(diào)的,反序列化時(shí),如果定義了readResolve()則直接返回此方法指定的對(duì)象,而不需要在創(chuàng)建新的對(duì)象!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容