因为大四快要找工作的问题,所以有想好好看看面试书。但是因为有实习每天回来都很晚也懒得看书,所以借博客督促下自己。
- 那首先简单的说明下什么是Singleton模式?为什么要用Singleton模式?什么情况下使用它?
Signleton是单例模式,是软件开发过程当中设计模式的一种,也是比较简单的一种。单例模式就是一个类只能提供一个唯一的实例,而且这个实例还是它自己创建的。使用单例模式有哪些好处呢?那假如把你的程序看做成千上万的军队,那单例模式生成的这个对象就是这支队伍唯一的指挥官,而不是一个军队有好多个指挥官。这样子整支军队也是乱的不成样子了。再具体点就是譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler,这样子就不会有同时多个打印作业涌进一个打印机了。 接下来看下如何实现单例模式:
- 解法一:我们把一个类的一个实例设置为私有的,静态的实例,只在它需要的时候创建这个实例。
public class Singleton1
{
private Signleton1()
{
}
private static Signleton1 instance =null;
public static getInstance(){
if(instance==null){
instance = new Signleton1();
}
return instance;
}
但是上面这种解法只能用于单线程的环境,在多线程的条件下两个线程同时判断 instance==null
的if语句的时候,都发现此时instance没有创建,那么它们都会创建一个实例,那这个类就不是单例模式了。
- 解法二:在多线程的情况下我们想要得到一个单例模式的类,那我们改造上面的这个方法,给它加一个同步锁。
public class Singleton2
{
private Signleton2()
{
}
private static Signleton2 instance =null;
public static synchronized getInstance(){
if(instance==null){
instance = new Signleton2();
}
return instance;
}
那我们现在看看上面的这种情况会出现什么问题。我们还是假设会有两个线程同时访问这个类来创建实例。在同一时刻只能有一个线程来得到同步锁,当第一个线程有锁的时候,第二个线程是不能进行创建实例这个操作的。第一个线程发现还没有实例存在,那好它创建了一个实例。然后第一个线程释放了锁,第二个线程开始加上锁。那第二个线程想要创建实例的时候发现实例存在了所以它就不会再去创建实例了。但这种方法是不是完美呢?当然不是了,线程的加锁是一个费时的操作。我们每次得到这样的一个实例,就会尝试去加锁,这样程序的性能就不是很完美了。
- 解法三:在实例没有创建好之前我们就给它上锁,当实例创建好之后实例就不会被加锁了。
public class Singleton3
{
private Signleton3()
{
}
private static Signleton3 instance =null;
public static synchronized getInstance(){
if(instance==null){
synchronized(Signleton3.class){
if(instance==null){
instance = new Signleton3();
}
}
}
return instance;
}
这种方法呢就比上面的好了很多,但是代码就很复杂不是很符合面试官心里的最佳答案。
- 解法四:我们按照需要来创建实例。
public class Singleton4
{
private Signleton4()
{
}
private static class Nested{
private static final Signleton4 = new Signleton4();
}
private static Signleton4 INSTANCE=null;
public static final Signleton4 getInstance(){
return Nested.INSTANCE;
}
}
最后的这种解法呢,是考虑比较周全。面试官看了之后会比较满意的一种,我们在内部定义一个静态的私有的类,当第一次用着这个Signleton4类的时候,会调用静态类Nested的构造方法创建Signleton4的实例,那如果我们再次使用的时候这个实例也已经存在了,我们不需要再去实例化Signleton4。从而实现了不使用同步锁也能保证线程是安全的。