线程安全问题-单例设计模式

第一种:饿汉式单例设计模式

在类加载的时候就创建好了一个静态的对象供系统使用,以后不再改变,所以天生就是线程安全的。

但是初始化就占用了系统的资源。

package thread;

/*
 * 饿汉式单例模式:饿汉式在类一创建的时候就已经创建好了一个静态的对象供系统使用,以后不再改变,所以天生就是线程安全的
 */

class Singleton3{
    private Singleton3(){
        
    }
    
    private static final Singleton3 INSTANCE = new Singleton3();
    
    public static Singleton3 getInstance(){
    
        return INSTANCE;
        
    }
}

//这里为了测试多线程并发调用单例对象,所以使用了多线程,即创建线程任务对象
class Demo3 implements Runnable{

    @Override
    public void run() {
        Singleton3 instance = Singleton3.getInstance();
        System.out.println(Thread.currentThread().getName()+"..."+instance);
    }
    
}
public class ThreadDemo3{

    public static void main(String[] args) {
        //创建线程任务对象
        Demo3 d3 = new Demo3();
        //创建三个线程对象
        Thread t1 = new Thread(d3);
        Thread t2 = new Thread(d3);
        Thread t3 = new Thread(d3);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }

}

运行结果:

 

第二种:懒汉式单例设计模式

懒汉式本身是不可以实现单例模式的,这里是通过同步代码块来实现的。

只有在第一次调用获取对象方法的时候才去初始化这个单例对象。

package thread;
/*
 * 懒汉式本身是不可以实现单例模式的,这里是通过判断和同步代码块完成的
 * 懒汉式单例模式:只有在第一次调用getInstance的时候初始化这个单例
 */
class Singleton4{
    private Singleton4(){}
    private static Singleton4 instance = null;
    public static Singleton4 getInstance() throws InterruptedException{
        /*
         * 这里为了方便测试多线程并发的情况更加准确
         * 让所有调用该线程的方法谁20毫秒,这样cpu的时间片可以充分的让其他线程也走到这一步
         */
        Thread.sleep(20);
        if (instance == null) {
            /*
             * 让所有的线程走过上面代码的线程,在进入同步代码块前,都睡20毫秒
             * 这样会有多个线程准备进入同步代码块
             */
            Thread.sleep(20);
            synchronized (Singleton4.class) {
                //让进入当前同步代码块的代码睡20毫秒,当然此时其他线程肯定是在外面等着的
                Thread.sleep(20);
                if (instance == null) {//加这一层的判断,是为了让其他准备进入的同步代码块知道,如果已经有一个线程实话了对象,他们就不用再次实话对象了
                    instance = new Singleton4();
                }
            }
        }
        return instance;
        
    }
    
    
}

class Demo2 implements Runnable{

    @Override
    public void run() {
        Singleton4 instance = null;
        try {
            instance = Singleton4.getInstance();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"..."+instance);
        
    }
    
}

public class ThreadDemo4{
    public static void main(String[] args) {
        //创建实现了Runable接口的线程任务对象
        Demo2 d = new Demo2();
        //创建三个并发线程进行测试
        Thread t1 = new Thread(d);
        Thread t2 = new Thread(d);
        Thread t3 = new Thread(d);
        //开启线程,让cpu时间片切调用run方法
        t1.start();
        t2.start();
        t3.start();
    }
    
}

运行结果:

 

第三种方式:静态内部类

为什么可以实现单例模式:静态内部类只会在第一调用的时候被加载一次,所以是线程安全的

package thread;

class Singleton5{

    private Singleton5(){}
    private static class lazyHoler{
        private static final Singleton5 INSTANCE = new Singleton5();
    }
    
    public static Singleton5 getInstance(){
        return lazyHoler.INSTANCE;
    }
}

//线程任务类
class Demo5 implements Runnable{

    @Override
    public void run() {
        Singleton5 instance = Singleton5.getInstance();
        System.out.println(Thread.currentThread().getName()+"..."+instance);
        
    }
    
}
public class ThreadDemo5 {
    public static void main(String[] args) {
        
        //创建线程任务对象
        Demo5 d5 = new Demo5();
        Thread t1 = new Thread(d5);
        Thread t2 = new Thread(d5);
        Thread t3 = new Thread(d5);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
        
    }

}

运行结果:

转载于:https://www.cnblogs.com/zhouxuan323/p/5176954.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值