单例模式 和 多线程

饿汉模式又称为立即加载模式,含以上就是非常急

也就是在使用类的时候已经将对象创建完毕

package lock;

public class EhanSingleton {

    /*饿汉加载模式/立即加载模式*/

    //初始化构造函数
    private  EhanSingleton(){

    }
    private  static EhanSingleton  ehan = new EhanSingleton();

    public static  EhanSingleton getInstance(){
        try {
            Thread.sleep(3000);   //方便多线程测试
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
          return  ehan ;
    }

}

然后我们用简单的多线程测试

package lock;

public class MyThread  extends  Thread{

     @Override
    public void run() {
             System.out.println(EhanSingleton.getInstance().hashCode());

    }
     public static void main(String[] args) {
            MyThread m1 = new MyThread();
            MyThread m12 = new MyThread();
            MyThread m13 = new MyThread();

            m1.start();
            m12.start();
            m13.start();
    }
}

126720696

126720696
126720696

算出来的结果每个对象的   hashcode的值是一样的,说明这个模式是符合单例模式的,这个也就是立即加载型单例设计模式

第二种单例模式        懒汉模式/延迟加载

这个方式是只有调用某个方法的时候才能调用这个实例

package lock;

public class LanHanSingleton {

    /*懒汉模式/延迟加载*/

    //私有化构造函数
    private LanHanSingleton(){

    }

    private  static LanHanSingleton lanHanSingleton ; 

    public  static  LanHanSingleton  getInstance() {
           if(lanHanSingleton == null){
                try {
                    Thread.sleep(3000);
                     lanHanSingleton = new LanHanSingleton() ;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

           }
          return lanHanSingleton ;
    }

}

我在用多线程去测试一下是否每个对象的HashCode的值是保持一致的

package lock;

public class MyThread  extends  Thread{

     @Override
    public void run() {
             System.out.println(LanHanSingleton.getInstance().hashCode());

    }
     public static void main(String[] args) {
            MyThread m1 = new MyThread();
            MyThread m12 = new MyThread();
            MyThread m13 = new MyThread();

            m1.start();
            m12.start();
            m13.start();
    }
}

126720696
137014984
1638443495

测试的结果发现 这个已经不符合单例模式,他们并不是同一个对象了,而是几个不同的对象,所以这种懒汉模式在单线程中是符合单例模式的,不过在多线程环境中是不符合单例模式

想到这里,大家肯定会想到了synchrinized关键字,我们在来看看效果

package lock;

public class LanHanSingleton {

    /*懒汉模式/延迟加载*/

    //私有化构造函数
    private LanHanSingleton(){

    }

    private  static LanHanSingleton lanHanSingleton ; 

    public synchronized  static  LanHanSingleton  getInstance() {
           if(lanHanSingleton == null){
                try {
                    Thread.sleep(3000);
                     lanHanSingleton = new LanHanSingleton() ;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

           }
          return lanHanSingleton ;
    }

}

运行结果:

1638443495
1638443495
1638443495

大家发现这样的确可以解决多线程带来的不同对象所导致的问题,但是这个方法并不好,这种方法效率非常低下,一定要等到上一个线程释放锁以后才能获取对象

同步方法是对整个方法持有锁,这个对于效率来说实在太慢,大家还会想到用同步块,那么我们在试一试

package lock;

public class LanHanSingleton {

    /*懒汉模式/延迟加载*/

    //私有化构造函数
    private LanHanSingleton(){

    }

    private  static LanHanSingleton lanHanSingleton ; 

    public   static  LanHanSingleton  getInstance() {
           try {
             synchronized (LanHanSingleton.class) {
                 if(lanHanSingleton == null){
                        Thread.sleep(3000);
                         lanHanSingleton = new LanHanSingleton() ;
               }
            }   

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

          return lanHanSingleton ;
    }

}

其实这个效果和上个效果差不多,效率都是比较慢的,和同步方法synchronized一样是同步运行的

这里最好的方式就是DCL双检查锁机制

package lock;

public class LanHanSingleton {

    /*懒汉模式/延迟加载*/

    //私有化构造函数
    private LanHanSingleton(){

    }

    private  static LanHanSingleton lanHanSingleton ; 

    public   static  LanHanSingleton  getInstance() {
           try {

                 if(lanHanSingleton == null){
                     synchronized (LanHanSingleton.class) {
                         if(lanHanSingleton == null){
                             lanHanSingleton = new LanHanSingleton() ;
                         }

                     }
               }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

          return lanHanSingleton ;
    }

}

还有一种的就是内部类的方式

package lock;

import java.io.ObjectStreamException;
import java.io.Serializable;

public class MyObject implements Serializable{

      private MyObject(){

      }

      private static class  MyObjectHander{
           private static  MyObject myObject = new MyObject();
      }

      public  static  MyObject getInstance(){
           return  MyObjectHander.myObject;
      }

//      public   MyObject readResolve() throws ObjectStreamException {
//          System.out.println("这个方法被调用了");
//          return MyObjectHander.myObject;
//      }

}

这个是内部类的方式,不过这个内部的方式还是有存在问题的肯能,这个虽然可以达到多线程单例模式的情况,不过如果遇到序列化的情况下就会违反单例模式的准则。。。。。

注释的方法就是为了序列化所提供的

package lock;

import java.io.ObjectStreamException;
import java.io.Serializable;

public class MyObject implements Serializable{

    private static final long serialVersionUID = 1L;

      private MyObject(){

      }

      private static class  MyObjectHander{
           private static final MyObject myObject = new MyObject();
      }

      public  static  MyObject getInstance(){
           return  MyObjectHander.myObject;
      }

      protected   MyObject readResolve() throws ObjectStreamException {
          System.out.println("这个方法被调用了");
          return MyObjectHander.myObject;
      }

}
package lock;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class CheckSingletonHashCode {

      public static void main(String[] args) {

            try {
                MyObject myObject = MyObject.getInstance();
                FileOutputStream os = new FileOutputStream(new File("D://lol.txt"));
                ObjectOutputStream oos = new ObjectOutputStream(os);
                  oos.writeObject(myObject);
                  oos.close();
                  os.close();
                  System.out.println(myObject.hashCode());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

         try {
                FileInputStream is = new FileInputStream(new File("D://lol.txt"));
                ObjectInputStream ois = new ObjectInputStream(is);
                  MyObject myObject = (MyObject) ois.readObject();
                  ois.close();
                  is.close();
                  System.out.println(myObject.hashCode());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }catch (ClassNotFoundException | IOException e) {
                e.printStackTrace();
            }

    }

}
时间: 2024-08-05 18:48:07

单例模式 和 多线程的相关文章

单例模式与多线程

概述 关于一般单例模式的创建和分析在我的另一篇博客<Java设计模式--单件模式>中有详细说明.只是在上篇博客中的单例是针对于单线程的操作,而对于多线程却并不适用,本文就从单例模式与多线程安全的角度出发,讲解单例模式在多线程中应该如何被使用. 版权说明 著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 本文作者:Coding-Naga 发表日期: 2016年4月6日 本文链接:http://blog.csdn.net/lemon_tree12138/article/det

单例模式在多线程中的使用情况

废话不多说,直接上代码: class MyThreadScopeData{ private MyThreadScopeData(){} private static MyThreadScopeData instance; //单例设计模式 public static MyThreadScopeData getInstance(){ if(instance ==null){ instance = new MyThreadScopeData(); } return instance; } } 上述代

单例模式在多线程环境下的lazy模式为什么要加两个if(instance==null)

刚才在看阿寻的博客”C#设计模式学习笔记-单例模式“时,发现了评论里有几个人在问单例模式在多线程环境下为什么lazy模式要加两个if进行判断,评论中的一个哥们剑过不留痕,给他们写了一个demo来告诉他们为什么. 我看了一下这个demo,确实说明了这个问题,但我认为不够直观,呵呵,于是我就稍微的改了一下. 这是剑过不留痕的demo using System; using System.Threading; namespace SingletonPattern { class Program { s

Java多线程核心技术(五)单例模式与多线程

本文只需要考虑一件事:如何使单例模式遇到多线程是安全的.正确的 1.立即加载 / "饿汉模式" 什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接 new 实例化. public class MyObject { private static MyObject myObject = new MyObject(); public MyObject(){ } public static MyObject getInstance(){ return myObj

如何保证单例模式在多线程中的线程安全性

对大数据.分布式.高并发等知识的学习必须要有多线程的基础.这里讨论一下如何在多线程的情况下设计单例模式.在23中设计模式中单例模式是比较常见的,在非多线程的情况下写单例模式,考虑的东西会很少,但是如果将多线程和单例模式结合起来,考虑的事情就变多了,如果使用不当(特别是在生成环境中)就会造成严重的后果.所以如何使单例模式在多线程中是安全的显得尤为重要,下面介绍各个方式的优缺点以及可用性: 1.立即加载(饿汉模式) 立即加载模式就是在调用getInstance()方法前,实例就被创建了,例: pub

浅淡java单例模式结合多线程测试

本人才疏学浅,正好利用博客这个平台整理下思路 使用单例模式简单来说生成对象时属性都一样,即你new一百次,通过方法得到的结果都一样(比如获取静态资源文件,工具类等). 所以就没必要生成多个对象浪费服务器内存,他和静态类又不同,因为单例本质也是对象系统,长期不使用,也会给cg清除.但是静态类不同,静态类的成员变量和有静态方法会在程序的整个生命周期存在,比如在服务器内在中加载后服务器不关,就会一直存在,同理的有servlet的ServletContext对象和jsp的application对象 单例

彻头彻尾理解单例模式与多线程

摘要: 本文首先概述了单例模式产生动机,揭示了单例模式的本质和应用场景.紧接着,我们给出了单例模式在单线程环境下的两种经典实现:饿汉式 和 懒汉式,但是饿汉式是线程安全的,而懒汉式是非线程安全的.在多线程环境下,我们特别介绍了五种方式来在多线程环境下创建线程安全的单例,使用 synchronized方法.synchronized块.静态内部类.双重检查模式 和 ThreadLocal 实现懒汉式单例,并总结出实现效率高且线程安全的单例所需要注意的事项. 版权声明: 本文原创作者:书呆子Rico

单例模式在多线程下的多种实现模式

单例模式是23种设计模式中比较常见的设计模式,又因为其代码量精简,所以经常会被用在在面试中测试面试者的能力. 初级的单例模式很简单 实现两个要求 1构造方法私有化 2对外提供静态的,公开的获取对象的方法 所以:初级单例模式如下 public class Singelton {private Singelton(){} private static Singelton sin=null;public static Singelton getSingelton(){           if(sin

6 单例模式及其多线程问题

一.单例模式 单例模式可以保证一个类仅有一个实例,这个模式应该更简单工厂一样常用了吧,但对我来说,以前都是瞎用,这是第一次深度学习单例模式. 最简单的单例模式代码是这样的: class Singleton { private static Singleton _instance; private Singleton() { } public static Singleton GetInstance() { if (_instance == null) _instance = new Single