单例模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。我们听说比较多的就是单例模式,工厂模式,代理模式。
单例模式,或者叫单例设计模式,就是采用一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
所以这就要求我们把类的构造方法的访问权限设置成private,这样在类的外部就不能使用new产生类的对象了。这个唯一的对象,我们只在类的内部产生。类的外部如果想得到这个对象可以调用该类的静态方法返回。又因为静态方法只能访问静态成员变量,所以这个对象还得声明成静态的。
比较熟悉的有几种实现方式,如饿汉式、懒汉式。
单例模式的饿汉式实现
饿汉:还没用就造好了。
class Singleton {
private Singleton() {
}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class Main {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2); //true,地址值一样,一个对象
}
}
单例模式的懒汉式实现
懒汉:什么时候用什么时候造。
class Singleton {
private Singleton() {
}
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2); //true
}
}
饿汉式和懒汉式的对比
项目 | 好处 | 坏处 |
---|---|---|
饿汉式 | 线程安全的 | 对象加载时间过长 |
懒汉式 | 延迟对象的创建 | 线程不安全 |
懒汉式的线程不安全演示
除了main主线程外,我们再创建一个线程,为了让效果更明显,我们在Singleton创建对象前sleep(1000)。
class Singleton {
private Singleton() {
}
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton();
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton instance1 = Singleton.getInstance();
System.out.println(instance1); //Singleton@75c85ca
}
}).start();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance2); //Singleton@4554617c
}
}
线程安全的懒汉式
使用同步代码块即可。
class Singleton {
private Singleton() {
}
private static Singleton instance = null;
public static Singleton getInstance() {
//这个判断条件可以过滤一部分线程
if (instance == null) {
synchronized (Singleton.class) {
//对于进入同步代码块的线程再判断一次
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
public class Main {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Singleton instance1 = Singleton.getInstance();
System.out.println(instance1); //Singleton@4554617c
}
}).start();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance2); //Singleton@4554617c
}
}
面试的时候要么写饿汉式,要么写线程安全的懒汉式。