单例模式:
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
优点:1.在内存中只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2.避免对资源的多重占用。
还可以使用在某些特定的场景中:这一个类只能有一个对象。
实现的基本思路:
1.不能随意的创建对象-私有化构造器。
2.唯一的对象作为类的静态属性,该对象只能初始化一次。
3.提供一个可以返回唯一对象的方法。
实现方式1-饿汉式:
public class SingleExampleHungry {
private String name ;
private Integer age;
//私有化的构造器,不允许外部私自创建对象。
private SingleExampleHungry(){
}
//私有化的类的对象。
private static final SingleExampleHungry seh = new SingleExampleHungry();
//提供一个可以返回对象的方法。
public static SingleExampleHungry getInstance(){
return seh;
}
//私有属性的getter和setter方法。
}
这种方式是通过先预先创建好对象,当需要创建该类的对象时就直接提供,用时间代替空间,等待调用,线程安全。
另一种饿汉式实现方式-静态初始化块。
public class SingleExampleLasy {
private String name;
private Integer age;
private Integer sex;
/*私有化一个该类的对象,并且是静态的,只能创建一次。*/
private static SingleExampleLasy se;
/*私有化构造器*/
private SingleExampleLasy() {
super();
}
/*创建对象的方法,如果创建的对象不为null就直接返回,为null就重新创建一个。*/
public static SingleExampleLasy getInstance(){
if(se==null){
se= new SingleExampleLasy();
}
return se;
}
public static SingleExampleLasy getInstance(String name , Integer age,Integer sex){
if(se==null){
se = new SingleExampleLasy();
se.age=age;
se.name=name;
se.sex=sex;
}
return se;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
}
public class SingleExampleHungryChange {
private String name;
private Integer age;
private static SingleExampleHungryChange sehc;
private SingleExampleHungryChange(){}
static{
sehc = new SingleExampleHungryChange();
}
public SingleExampleHungryChange getInstance(){
return sehc;
}
//私有属性的getter和setter方法。
}
以上两种处理方式都是在类加载时就将对象创建完毕,等待调用。
存在的缺点:浪费内存资源,不管这个类是否需要被实例化,都会创建对象,而且当这个类被多次加载时,也会创建多个对象。
实现方式2-懒汉式:
与饿汉式不同,懒汉式采取的方式是与正常创建对象类似,需要该类创建对象时才创建,但是只能只创建一次。用空间代替时间,但是会存在线程安全问题。
public class SingleExampleLasy {
private String name;
private Integer age;
private Integer sex;
/*私有化一个该类的对象,并且是静态的,只能创建一次。*/
private static SingleExampleLasy se;
/*私有化构造器*/
private SingleExampleLasy() {
super();
}
/*创建对象的方法,如果创建的对象不为null就直接返回,为null就重新创建一个。*/
public static SingleExampleLasy getInstance(){
if(se==null){
se= new SingleExampleLasy();
}
return se;
}
public static SingleExampleLasy getInstance(String name , Integer age,Integer sex){
if(se==null){
se = new SingleExampleLasy();
se.age=age;
se.name=name;
se.sex=sex;
}
return se;
}
//私有属性的getter和setter方法。
}
这种处理方式存在线程安全问题:
当第一个线程创建该类对象时,因为未知原因阻塞。第二个线程开始创建对象,就会导致创建多个对象,不符合单例模式的基本 目的。
通过增加同步锁的方式来提高线程安全。
public class SingleExampleChange {
private String name ;
private Integer height;
private static SingleExampleChange sec;
private SingleExampleChange(){
}
/*修饰符synchronized 实现同步锁的需求*/
private static synchronized void createObject(){
if(sec == null){
sec = new SingleExampleChange();
}
}
public static SingleExampleChange getInstance(){
createObject();
return sec;
}
public static SingleExampleChange getInstance(String name , Integer height){
createObject();
sec.name=name;
sec.height=height;
return sec;
}
//私有属性的getter和setter方法。
}
以上方式通过加同步锁的方式可以实现线程安全,但是还是存在效率低的问题,可以通过加双层同步锁的方式来解决,这里我还没有理解透彻,先待定。
实现方式3-枚举法:
public enum SingleExample {
INSTANCE;
public void SingleExample(){
}
}
枚举法防止了反序列化等问题。这个实现方法还没有理解,先待定。