一、什么是单例模式?
单例模式,也叫单子模式,是一种对象创建型模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。
二、为什么要使用单例模式?
许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
三、实现思路:
一个类能返回对象的一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
四、多线程与单例模式
单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。
五、主要代码:
/**
* @Title: Person.java
* @Package
* @Description: 单例模式的第一种形式 --懒汉方式。指全局的单例实例在第一次被使用时构建。
* @author xiaozhi
* @date 2016年11月30日 下午8:01:58
* @version V1.0
*/
public class Person {
//在开始创建的时候就直接初识化该对象,不论单线程和多线程都比较安全,但比较耗费资源
public static final Person person =new Person();
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Person(){}
public static Person Person(){
return person;
}
}
/**
* @Title: Person.java
* @Package
* @Description: 单例模式的第二种形式--饿汉方式。指全局的单例实例在类装载时构建。
* 未解决多线程的问题
* @author xiaozhi
* @date 2016年11月30日 下午8:01:58
* @version V1.0
*/
public class Person2 {
public String name;
private static Person2 person2;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Person2(){}
//创建一个全局的静态方法
public static Person2 getPerson(){
if(person2==null){
person2 =new Person2();
}
return person2;
}
}
/**
* @Title: Person.java
* @Package
* @Description: 单例模式的第二种形式---饿汉方式。指全局的单例实例在类装载时构建。
* @author xiaozhi
* @date 2016年11月30日 下午8:01:58
* @version V1.0
*/
public class Person3 {
public String name;
private static Person3 person2;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Person3(){}
/**
*
* @Title: getPerson
* @Description: 比起Person2类中,多了 synchronized(同步),用来阻止多个线程同时进入getPerson方法,
* 当第一个线程进入时,在该线程结束前,阻止其他线程进入。
* @param @return 设定参数
* @return Person3 返回类型
* @throws
*/
//创建一个全局的静态方法,使用同步的方法 ,解决了多线程的问题
public static synchronized Person3 getPerson(){
if(person2==null){
person2 =new Person3();
}
return person2;
}
}
/**
* @Title: Person.java
* @Package
* @Description: 单例模式的第二种形式---饿汉方式。指全局的单例实例在类装载时构建。
* @author xiaozhi
* @date 2016年11月30日 下午8:01:58
* @version V1.0
*/
public class Person4 {
public String name;
private static Person4 person4;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private Person4(){}
/**
*
* @Title: getPerson
* @Description: 为了解决Person3在第一个线程进入,而还没创建完,导致其他线程等待的问题,
* 则在内部采用双重检查的方式。
* @param @return 设定参数
* @return Person4 返回类型
* @throws
*/
//创建一个全局的静态方法,使用双重检查的方法 ,解决了多线程的问题
public static Person4 getPerson(){
//第一层。一般能解决多个线程不在极短时间内进入的部分。
if(person4==null){
//只需要在创建的时候保持同步
synchronized(Person4.class){
//第二层。解决当多个线程同时进入时(person4==null),第一个线程创建完并返回,其他和第一个线程一起进来还能再继续创建的问题。
if(person4 == null){
person4 =new Person4();
}
}
}
return person4;
}
}
/**
* @Title: MainClass.java
* @Package
* @Description: 测试类
* @author xiaozhi
* @date 2016年11月30日 下午8:02:11
* @version V1.0
*/
public class MainClass {
public static void main(String[] args) {
// Person p=Person.Person();
// p.setName("zhangsan");
// Person p1=Person.Person();
// p1.setName("lisi");
// System.out.println(p.name);
// System.out.println(p1.name);
// Person2 p=Person2.getPerson();
// p.setName("zhangsan");
// Person2 p1=Person2.getPerson();
// p1.setName("lisi");
// System.out.println(p.name);
// System.out.println(p1.name);
Person4 p=Person4.getPerson();
p.setName("zhangsan");
Person4 p1=Person4.getPerson();
p1.setName("lisi");
System.out.println(p.name);
System.out.println(p1.name);
}
}
六、运行结果:
lisi
lisi