单例的目的是保证某个类仅有一个实例。当有某些类创建对象内存开销较大时可以考虑使用该模式。单例模式又分为 饿汉式 和 懒汉式 。下面分别说明:
1.饿汉式。顾名思义,该模式在类被加载时就会实例化一个对象。具体代码如下:
public class Person {
//饿汉式单例
private static Person person = new Person();
private Person(){}
public static Person getInstance(){
return person;
}
}
该模式能简单快速的创建一个单例对象,而且是线程安全的(只在类加载时才会初始化,以后都不会)。但它有一个缺点,就是不管你要不要都会直接创建一个对象,会消耗一定的性能(当然很小很小,几乎可以忽略不计,所以这种模式在很多场合十分常用而且十分简单)
2.懒汉式。该模式只在你需要对象时才会生成单例对象(比如调用getInstance方法)
public class User {
//懒汉式单例,只有在调用getInstance时才会实例化一个单例对象
public static User user;
private User(){
}
public static User getInstance(){
if(user==null){ //step 1.
user = new User(); //step 2
}
return user;
}
}
看上去,这段代码没什么明显问题,但它不是线程安全的。假设当前有N个线程同时调用getInstance()方法,由于当前还没有对象生成,所以一部分同时都进入step 2,
那么就会由多个线程创建多个多个user对象。
解决办法:使用synchronized关键字。经改造上面代码展示如下:
public class User {
//懒汉式单例,只有在调用getInstance时才会实例化一个单例对象
public static User user;
public static Integer key = new Integer(4); //作为一个锁
private User(){
}
public static User getInstance(){
//先判断该user变量是否为空,入股为空,进入同步代码块,该步假设为step1
if(user == null){ //step 1 //想象一下,如果不判断,那么每次访问这个方法不管该对象是否已经创建都要进入同步代码块,线程数一多,资源消耗也是非常巨大的。
synchronized (key) {
//由于可能多个线程都进入了step1,由于锁定机制,一个线程进入该代码块时,其他线程
//仍在排队进入该代码块,如果不做判断,当前线程即使创造了实例,下一个线程也不知道,就会继续创建一个实例
if(user==null){
user = new User();
}
}
}
return user;
}
}
通过上面的锁机制同步代码块就可以写出线程安全的懒汉式单例。
参考文档:https://blog.csdn.net/SummerMangoZz/article/details/57080540
来源:oschina
链接:https://my.oschina.net/u/4256408/blog/3520792