单例模式和多线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35974759/article/details/89489694

title: 对象及变量的并发访问
categories: Java多线程编程核心技术
tags: 多线程
time: 2019-04-24 11:44:32

立即加载/饿汉模式

立即加载就是在使用类之前已经将对象创建完毕,常见的实现方法就是new实例化。

public class MyThread {

    private static MyThread INSTANCE = new MyThread();
    private MyThread() {}
    public static MyThread getInstance() {
        return INSTANCE;
    }
}

class Test {
    public static void main(String[] args) {
        ThreadA a = new ThreadA(MyThread.getInstance());
        a.start();
        ThreadA b = new ThreadA(MyThread.getInstance());
        b.start();
        ThreadA c = new ThreadA(MyThread.getInstance());
        c.start();
    }
}

class ThreadA extends Thread {
    private MyThread myThread;

    public ThreadA(MyThread myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}


class ThreadB extends Thread {
    private MyThread myThread;

    public ThreadB(MyThread myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}

class ThreadC extends Thread {
    private MyThread myThread;

    public ThreadC(MyThread myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}

运行结果:

Thread-0 1315983110
Thread-2 1315983110
Thread-1 1315983110

3个线程运行后得到相同的一个hashcode值,说明对象是同一个,也就实现了立即加载型单例设计模式
立即加载,缺点是不能有其他实例变量,因为getInstance方法没有同步,所以有可能会出现线程不安全问题。

延迟加载/懒汉模式

延迟加载就是在执行get方法后才会去创建对象,常见的方式就是在调用get方法后用new实例化。

public class MyThread1 {

    private static MyThread1 instance;

    private MyThread1(){}

    synchronized public static MyThread1 getInstance() {
        if (instance == null) {
           instance = new MyThread1();
        }
        return instance;
    }
}

class Test2 {
    public static void main(String[] args) {
        ThreadE e = new ThreadE(MyThread.getInstance());
        e.start();
        ThreadD d = new ThreadD(MyThread.getInstance());
        d.start();
    }
}

class ThreadE extends Thread {
    private MyThread myThread;

    public ThreadE(MyThread myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}


class ThreadD extends Thread {
    private MyThread myThread;

    public ThreadD(MyThread myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}

运行结果:

Thread-0 985847520
Thread-1 985847520

使用的是同步方法的方式,效率比较低下,可以用同步代码块进行优化

public static MyThread1 getInstance() {
        if (instance == null) {
            synchronized (MyThread1.class) {
                instance = new MyThread1();
            }
        }
        return instance;
    }

但是在多线程中仍然无法解决得到同一个实例对象的结果。
解决方式:使用DCL双重锁检查机制

使用DCL双检查锁机制

public class MyThread3 {

    private static MyThread3 instance;

    private MyThread3(){}

    public static MyThread3 getInstance() {
        if (instance == null) {
            synchronized (MyThread1.class) {
                if (instance == null) {
                    instance = new MyThread3();
                }
            }
        }
        return instance;
    }
}
class Test3 {
    public static void main(String[] args) {
        ThreadF e = new ThreadF(MyThread3.getInstance());
        e.start();
        ThreadG d = new ThreadG(MyThread3.getInstance());
        d.start();
    }
}

class ThreadF extends Thread {
    private MyThread3 myThread;

    public ThreadF(MyThread3 myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}


class ThreadG extends Thread {
    private MyThread3 myThread;

    public ThreadG(MyThread3 myThread) {
        this.myThread = myThread;
    }
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() +" " + myThread.hashCode());
    }
}

执行结果:

Thread-0 1211216510
Thread-1 1211216510

DCL很好的解决了懒汉式加载过程中多线程非线程安全的问题,DCL也是大多数多线程结合单例模式使用的解决方案。

静态内置类实现单例模式

public class MyThread4{

    private MyThread4(){}

    private static class MyThread3Holder {
        private static MyThread4 instance = new MyThread4();
    }

    public static MyThread4 getInstance() {
        return MyThread3Holder.instance;
    }

}

class Test4 {
    public static void main(String[] args) {
        ThreadH h = new ThreadH();
        ThreadI i = new ThreadI();
        h.start();
        i.start();
    }
}

class ThreadH extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyThread4.getInstance().hashCode());
    }
}
class ThreadI extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(MyThread4.getInstance().hashCode());
    }
}

运行结果:

726367991
726367991

序列化和反序列化单例模式实现

static 代码块实现单例模式

public class MyThread5 {

    private static MyThread5 instance;
    private MyThread5(){}

    static {
        instance = new MyThread5();
    }

    public static MyThread5 getInstance() {
        return instance;
    }
}

class Test5 {
    public static void main(String[] args) {
        ThreadM m = new ThreadM();
        ThreadN n = new ThreadN();
        m.start();
        n.start();
    }
}

class ThreadM extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() + " :" + MyThread5.getInstance().hashCode());
    }
}

class ThreadN extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName() + " :" + MyThread5.getInstance().hashCode());
    }
}

运行结果:

Thread-1 :726367991
Thread-0 :726367991

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

完善使用enum枚举实现单例模式

猜你喜欢

转载自blog.csdn.net/qq_35974759/article/details/89489694
今日推荐