java高级---->Thread之单例模式的使用

  这里我们介绍一下在多线程中如何安全正确的编写单例模式的代码。不知为何,恰如其分的话总是姗姗来迟,错过最恰当的时机。

多线程中的单例模式

  这里面通过代码来体会一下在多线程中如何正确的编写单例模式的代码。相同的代码如下,不同的是Object这个类。

package com.linux.huhx.thread3.singleDesign_1;

/**
 * @Author: huhx
 * @Date: 2017-10-31 下午 4:28
 */
public class SingleDesignTest1 {
    public static void main(String[] args) {
        MyThread[] threads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new MyThread();
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(MyObject*.getInstance().hashCode());
        }
    }
}

以下的不同测试类的结果,都是基于修改MyThread里面run方法的MyObject*的值。

一、立即加载方式(饿汉模式)

public class MyObject1 {
    private static MyObject1 myObject = new MyObject1();
    private MyObject1() {}

    public static MyObject1 getInstance() {
        return myObject;
    }
}

安全:一次的打印结果如下

1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770

二、延迟加载方式(懒汉模式)

public class MyObject2 {
    private static MyObject2 myObject;
    private MyObject2() {}

    public static MyObject2 getInstance() {
        try {
            if (myObject == null) {
                // 模拟一些准备的耗时操作
                TimeUnit.SECONDS.sleep(2);
                myObject = new MyObject2();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

不正确:一次的打印结果

401241377
355159803
1875573029
797782832
1696014491
1060834655
961745937
1060834655
1312341120
985396398

三、延迟加载解决方案之声明synchronized

public class MyObject3 {
    private static MyObject3 myObject;
    private MyObject3() {}

    public synchronized static MyObject3 getInstance() {
        try {
            if (myObject == null) {
                // 模拟一些准备的耗时操作
                TimeUnit.SECONDS.sleep(2);
                myObject = new MyObject3();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

安全:一次的打印结果

774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507

效率比较低下:同步运行,下一个线程想要取得对象,则必须等待上一个线程释放锁之后,才可以继续执行。

 四、延迟加载解决方案之同步代码块

public class MyObject4 {
    private static MyObject4 myObject;
    private MyObject4() {}

    public static MyObject4 getInstance() {
        try {
            synchronized (MyObject4.class) {
                if (myObject == null) {
                    // 模拟一些准备的耗时操作
                    TimeUnit.SECONDS.sleep(2);
                    myObject = new MyObject4();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

 安全:一次的打印结果如下

1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392

 效率比较低下:和上述的synchronized同步方法一样都是同步运行的。

五、延迟加载解决方案之同步部分代码块

public class MyObject5 {
    private static MyObject5 myObject;
    private MyObject5() {}

    public static MyObject5 getInstance() {
        try {
            if (myObject == null) {
                // 模拟一些准备的耗时操作
                TimeUnit.SECONDS.sleep(2);
                synchronized (MyObject5.class) {
                    myObject = new MyObject5();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

不安全:一次的打印结果如下

401241377
1696014491
797782832
1875573029
1060834655
43626537
1971360294
1312341120
961745937
860826410

六、延迟加载解决方案之DCL双检查锁机制

public class MyObject6 {
    private volatile static MyObject6 myObject;
    private MyObject6() {}

    public static MyObject6 getInstance() {
        try {
            if (myObject == null) {
                // 模拟一些准备的耗时操作
                TimeUnit.SECONDS.sleep(2);
                synchronized (MyObject6.class) {
                    if (myObject == null) {
                        myObject = new MyObject6();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

安全:一次的打印结果如下

1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120

使用双重检查锁功能,成功地解决了“懒汉模式”遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案。

七、使用静态内置类实现单例模式

public class MyObject7 {
    private static class MyObjectHandler {
        private static MyObject7 myObject = new MyObject7();
    }

    private MyObject7() {}

    public static MyObject7 getInstance() {
        return MyObjectHandler.myObject;
    }
}

安全:一次的打印结果如下

1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261

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

public class MyObject8 {
    private static MyObject8 myObject = null;

    static {
        myObject = new MyObject8();
    }

    private MyObject8() {}

    public static MyObject8 getInstance() {
        return myObject;
    }
}

安全:一次的打印结果如下

1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029

友情链接

原文地址:https://www.cnblogs.com/huhx/p/baseusejavasingleDesign.html