(3)Java设计模式-单例模式

  单例模式(Singleton)是一种较为常用的设计模式,单例对象能保证在JVM虚拟中,该对象只有一个实例存在。

  1.(懒汉,线程不安全)

 1 //单例模式
 2 public class Singleton {
 3     // 私有化构造方法防止对象在外部被实例化
 4     private Singleton() {
 5         System.out.println("create");
 6     }
 7
 8     // 私有化静态实例,防止实例被外部应用
 9     private static Singleton singleton = null;
10
11     public static Singleton getObject() {
12         if (singleton == null) {
13             singleton = new Singleton();
14         }
15         return singleton;
16     }
17
18 }

  测试类:

 1 public class test {
 2     public static void main(String[] args) {
 3         Singleton s1 = Singleton.getObject();
 4         System.out.println(s1.hashCode());//获取对象的编码,该编码是唯一值
 5         Singleton s2 = Singleton.getObject();
 6         System.out.println(s2.hashCode());
 7         Singleton s3 = Singleton.getObject();
 8         System.out.println(s3.hashCode());
 9     }
10 }

  运行结果:

create
366712642
366712642
366712642

从运行结果来看,对象只被实例化一次。且每次获取编码值都相同,这段代码可以满足基本需求,但是此类没有任何线程保护,遇到多线程环境,会出现问题。示例如下:

 1 //新增线程A类
 2 public class ThreadA implements Runnable {
 3
 4     @Override
 5     public void run() {
 6         Singleton s1 = Singleton.getObject();
 7         System.out.println(s1.hashCode());
 8     }
 9
10 }

  测试类

 1 public class test2 {
 2     public static void main(String[] args) {
 3         ThreadA2 a1 = new ThreadA2();
 4         ThreadA2 a2 = new ThreadA2();
 5         Thread therad1 = new Thread(a1);
 6         Thread therad2 = new Thread(a2);
 7         therad1.start();
 8         therad2.start();
 9     }
10 }

  运行结果:

create
79380705
create
1675705343

  这种毫无线程安全措施的懒汉模式,只适合在单线程的情况下运行,一旦加入多线程环境,会产生多个对象

  2.(懒汉,线程安全)

 1 //新的单例类
 2 public class Singleton2 {
 3     private Singleton2() {
 4         System.out.println("create");
 5     }
 6
 7     private static Singleton2 singleton = null;
 8
 9     // 加入synchronized关键字保证线程安全
10     public synchronized static Singleton2 getObject() {
11         if (singleton == null) {
12             singleton = new Singleton2();
13         }
14         return singleton;
15     }
16
17 }
 1 //新增线程A2类,调用新的单例类方法
 2 public class ThreadA2 implements Runnable {
 3
 4     @Override
 5     public void run() {
 6         Singleton2 s1 = Singleton2.getObject();
 7         System.out.println(s1.hashCode());
 8     }
 9
10 }

  测试类

 1 public class test2 {
 2     public static void main(String[] args) {
 3         ThreadA2 a1 = new ThreadA2();
 4         ThreadA2 a2 = new ThreadA2();
 5         Thread therad1 = new Thread(a1);
 6         Thread therad2 = new Thread(a2);
 7         therad1.start();
 8         therad2.start();
 9     }
10 }

  运行结果

create
1715342245
1715342245

  新的懒汉模式加入synchronized关键字,保证线程安全,但是正是由于同步锁,导致多个线程调用该方法时必须依次运行,而代码除了第一次运行时对象为空时才需要有线程锁,其他的时候都不需要,使代码运行效率极低。

3.饿汉模式

//新的单例类
public class Singleton3 {
    private Singleton3() {
        System.out.println("create");
    }

    private static Singleton3 singleton = new Singleton3();

    public static Singleton3 getObject() {
        return singleton;
    }

}

  测试类

 1 public class test3 {
 2     public static void main(String[] args) {
 3         Singleton3 s1 = Singleton3.getObject();
 4         System.out.println(s1.hashCode());
 5         Singleton3 s2 = Singleton3.getObject();
 6         System.out.println(s2.hashCode());
 7         Singleton3 s3 = Singleton3.getObject();
 8         System.out.println(s3.hashCode());
 9     }
10 }

  运行结果

create
366712642
366712642
366712642

  新的单例类也完成了单例任务,但是单例对象在类被装载的时候就已经初始化了,导致类被装载的情况有很多,加入该类中包含其他静态方法,导致类被装载,那么这时候初始化单例对象明显是没有达到我们需要的效果。

4.静态内部类

 1 //新的单例类
 2 public class Singleton4 {
 3     private static class SingletonHolder {
 4         private static final Singleton4 singleton = new Singleton4();
 5     }
 6
 7     private Singleton4() {
 8         System.out.println("create");
 9     }
10
11     public static final Singleton4 getObject() {
12         return SingletonHolder.singleton;
13     }
14 }

  运行结果

create
366712642
366712642
366712642

  这种方法和方法3同样利用classloder的机制来保证初始化instance时只有一个线程,但是区别是方法3只要单例类被加载,那么单例对象就会被初始化,而这种方法,但单例类被加载,其静态内部类没有被主动使用,那么静态内部类的里的单例对象同样不会被初始化,只有静态内部类被主动使用,其内的单例对象才会被初始化。可以看出这种方法比其他方法合理的多。

5.枚举

1 public enum Singleton5 {
2     INSTANCE;
3
4     private Singleton5() {
5         System.out.println("create");
6     }
7 }

  测试类

 1 public class test5 {
 2     public static void main(String[] args) {
 3         Singleton5 s1 = Singleton5.INSTANCE;
 4         System.out.println(s1.hashCode());
 5         Singleton5 s2 = Singleton5.INSTANCE;
 6         System.out.println(s2.hashCode());
 7         Singleton5 s3 = Singleton5.INSTANCE;
 8         System.out.println(s3.hashCode());
 9     }
10 }

  运行结果

1 create
2 366712642
3 366712642
4 366712642

  这个优秀的思想直接源于Joshua Bloch的《Effective Java》,这种方法不但能避免多线程同步问题,而且能防止反序列话重新创建新的对象。不过只有jdk1.5之后才可以用该方法,因为只有在此只有才加入了枚举的特性。

单例模式与类加载器的问题

 如果单例由不同的类加载器装入,那么我们就有可能得到多个单例类的实例,解决方法如下

 1     private static Class getClass(String classname)
 2                                              throws ClassNotFoundException {
 3           ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 4
 5           if(classLoader == null)
 6              classLoader = Singleton.class.getClassLoader();
 7
 8           return (classLoader.loadClass(classname));
 9        }
10     }  

单例模式与序列化的问题

  由于序列化的特性,序列化会通过反射调用午无参的构造函数创建一个新的对象,导致单例模式被破坏就,解决办法:

 1 import java.io.Serializable;
 2
 3 //新的单例类
 4 public class Singleton6 implements Serializable {
 5     private Singleton6() {
 6         System.out.println("create");
 7     }
 8
 9     private static Singleton6 singleton = new Singleton6();
10
11     public static Singleton6 getObject() {
12         return singleton;
13     }
14
15     // 避免序列化带来的影响
16     public Object readResolve() {
17         return singleton;
18     }
19 }

  

时间: 2024-12-05 00:41:48

(3)Java设计模式-单例模式的相关文章

Java设计模式の单例模式

-------------------------------------------------- 目录 1.定义 2.常见的集中单例实现 a.饿汉式,线程安全 但效率比较低 b.单例模式的实现:饱汉式,非线程安全 c.饱汉式,线程安全简单实现 d.线程安全 并且效率高  单例模式最优方案 3.总结 a.使用枚举的单例模式 b.使用枚举,static处调用,初始化一次 -------------------------------------------------- 1.定义 确保一个类只有

Java 设计模式 单例模式(Singleton) [ 转载 ]

Java 设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创建对象 第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton (){} 4 5 public static Singleton getInstan

Java设计模式-单例模式(Singleton)

单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销. 2.省去了new操作符,降低了系统内存的使用频率,减轻GC压力. 3.有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了.(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程. 单例

java设计模式 - 单例模式(干货)

深度讲解23种设计模式,力争每种设计模式都刨析到底.废话不多说,开始第一种设计模式 - 单例. 作者已知的单例模式有8种写法,而每一种写法,都有自身的优缺点. 1,使用频率最高的写法,废话不多说,直接上代码 /** * @author xujp * 饿汉式 静态变量 单例 */ public class Singleton implements Serializable { private static final long serialVersionUID = 1L; private fina

java设计模式--单例模式

单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 核心知识点如下: (1) 将采用单例设计模式的类的构造方法私有化(采用private修饰). (2) 在其内部产生该类的实例化对象,并将其封装成private static类型. (3) 定义一个静态方法返回该类的实例. /** * 方法一 * 单例模式的实现:饿汉式,线程安全 但效率比较低 */ public class Singl

Java设计模式—单例模式和模板模式

1.单例模式方法:类构造方法私有的,类里面有个静态类对象用来保存这个类对象,并且这个类提供获取该类对象的静态方法. /** * 单例设计模式 * @author Admin * */ public class Design1 { private String name; private static Design1 d; private Design1(String name){ this.name = name; } public static Design1 getDesign(){ if(

浅析Java设计模式 - 单例模式

以下是三种单例模式的代码实现,前两者用的比较多 (言外之意 最后一种可以忽略) 1 package com.signle; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * 8 * @title 单例模式 9 * @Copyright Copyright (c)2016年3月9日 10 * @Company CTC 11 * @version 1.0 12 * @author ejokovic 13 * @time

转!java设计模式--单例模式

作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 饿汉式单例类 public class EagerSingleton { private static EagerSingleton instance = new EagerSingleton(); /** * 私有默认构造子 */ private E

Java设计模式—单例模式

Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 核心知识点如下: (1) 将采用单例设计模式的类的构造方法私有化(采用private修饰). (2) 在其内部产生该类的实例化对象,并将其封装成private static类型. (3) 定义一个静态方法返回该类的实例. 一:饿汉模式 优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题:缺点是:当类Si