单例模式 : 一个类创建的 任何对象都是同一个只存在一个实例,都只开辟同一块内存空间
单例模式就是不管外部如何创建 都只是创建一个对象 对象操作的也是只个唯一对象
饿汉式:
public class Singleton { public static void main(String[] args) { Pattern patternOne = Pattern.getPattern(); Pattern patternTwo = Pattern.getPattern(); System.out.println(patternOne == patternTwo); // true 比较两个内存地址 } } // 饿汉式 单例模式 class Pattern{ // 私有化构造方法不允许外部随意调用 private Pattern(){} // 因为构造方法是创建对象来用的 我们不允许外部随意创建对象 // 内部创建对象 private static Pattern pattern = new Pattern(); // 对生产的对象私有化 并静态化 在内部创建完毕 // 提供公共的静态方法 返回已创建对象 public static Pattern getPattern(){ // 外部都只能通过此方法获取对象, 并且获取的都是同一个对象, 只开辟一块内存地址 return pattern; } }
懒汉式:
public class Singleton { public static void main(String[] args) { Lazy lazyOne = Lazy.getLazy(); Lazy lazyTwo = Lazy.getLazy(); System.out.println(lazyOne == lazyTwo); //true } } // 懒汉式 class Lazy { // 1: 私有化构造器 private Lazy() { } //2 : 内部创建类的对象 // 4: 要求此对象必须声明为static private static Lazy lazy = null; //3 : 向外部提供一个公共的static方法 public static Lazy getLazy() { if (lazy == null) { lazy = new Lazy(); //如果是空的时候就创建一个不然所有的都是没有在内部创建的对象,在外部就会创建 } return lazy; } }
懒汉式 和饿汉式 :
懒汉式 什么时候用什么时候造 饿汉式提前造好
饿汉式 VS 懒汉式
饿汉式: 坏处 对象加载时间过长 (提前创建好的 在内存中保留时间较久)
好处 :饿汉式 是线程安全
懒汉式 好处 延迟对象的创建
坏处 : 目前写法不安全 -- >多线程内部时修改
目前 :懒汉式线程不安全(当都去抢火车票 ,三个人一起刷票 然后都进入了是否为空的时候 然后第一个卡顿了 第二个第三个也进去了 最后三个人都会 去创建了对象就不是只创建一个对象了,而饿汉式提前创建好 ,不论如何卡顿 都是创建一个对象)
单例模式的优点
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的 产生需要比较多的资源时,
如读取配置、产生其他依赖对象时,则可 以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方 式来解决。
单例模式的应用场景
1: 网站的计数器,一般也是单例模式实现,否则难以同步。 2: 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志 文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。 3: 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库 资源。 4: 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。 5: Application 也是单例的典型应用 6:Windows的Task Manager (任务管理器)就是很典型的单例模式 7: Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程 中,回收站一直维护着仅有的一个实例。
解决懒汉式的线程安全
class BankTOne{ private BankTOne(){} private static BankTOne bankTOne = null; //方式一 /** public static synchronized BankTOne getBankTOne(){ // 此时 if(bankTOne == null){ bankTOne = new BankTOne(); } return bankTOne; } //上面的方法等于这种方法 public static BankTOne getBankTOne(){ synchronized(BankTOne.class){ if(bankTOne == null){ bankTOne = new BankTOne(); } return bankTOne; } } */ // 方式二 效率高, 这样第一个线程拿走最后一个的时候下面的线程就不用再进入其中了 public static synchronized BankTOne getBankTOne(){ if(bankTOne == null){ synchronized(BankTOne.class){ if(bankTOne == null){ bankTOne = new BankTOne(); } } } return bankTOne; } }