单件模式:
确保一个类只有一个实例,并提供全局访问点。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
如果在单线程中,我们可以这样做,但是程序大多是情况是在多线程的环境中,所以上面这段代码就会产生漏洞。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
class Test extends Thread {
public void run() {
System.out.println(Singleton.getInstance());
}
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
new Test().start();
}
}
}
为了说明结果,可以执行上面的这部分代码,你会发现有很多的线程都挤进了 getInstance() 方法,产生了多了实例。
通常产生单一实例的方法有 3 中,但每一种都有自己的局限性
1.适用于系统对性能 要求 不是很高的情况中。
public static synchronized Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
优点:实现简单。
缺点:如果访问这个方法的次数非常多,那么每一次访问都需要进行同步,会影响性能。通常同步的方法比普通的方法慢100倍。
2.在类装载时就进行创建。
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
优点:在加载时就进行了创建,实现简单。
缺点:不能延迟初始化,在对象加载是就已经浪费了性能。
3.采用 “双重检查加锁”
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
synchronized(Singleton.class) {
if(null == instance)
instance = new Singleton();
}
}
return instance;
}
}
优点:性能上得到了保证。
缺点:只能适用于1.5版本以后的程序。
注意:
1.如果有两个类装载器,加载同一个类,就会产生多个单件并存的情况,解决办法就是:指定同一个类加载器加载。
2.在java1.2之前,如果单件没有全局引用时,垃圾回收器会把这个单件当作垃圾进行回收。
确保一个类只有一个实例,并提供全局访问点。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
如果在单线程中,我们可以这样做,但是程序大多是情况是在多线程的环境中,所以上面这段代码就会产生漏洞。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(null == instance) {
instance = new Singleton();
}
return instance;
}
}
class Test extends Thread {
public void run() {
System.out.println(Singleton.getInstance());
}
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
new Test().start();
}
}
}
为了说明结果,可以执行上面的这部分代码,你会发现有很多的线程都挤进了 getInstance() 方法,产生了多了实例。
通常产生单一实例的方法有 3 中,但每一种都有自己的局限性
1.适用于系统对性能 要求 不是很高的情况中。
public static synchronized Singleton getInstance() {
if(null == instance) {
instance = new Singleton();
}
return instance;
}
优点:实现简单。
缺点:如果访问这个方法的次数非常多,那么每一次访问都需要进行同步,会影响性能。通常同步的方法比普通的方法慢100倍。
2.在类装载时就进行创建。
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
优点:在加载时就进行了创建,实现简单。
缺点:不能延迟初始化,在对象加载是就已经浪费了性能。
3.采用 “双重检查加锁”
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
synchronized(Singleton.class) {
if(null == instance)
instance = new Singleton();
}
}
return instance;
}
}
优点:性能上得到了保证。
缺点:只能适用于1.5版本以后的程序。
注意:
1.如果有两个类装载器,加载同一个类,就会产生多个单件并存的情况,解决办法就是:指定同一个类加载器加载。
2.在java1.2之前,如果单件没有全局引用时,垃圾回收器会把这个单件当作垃圾进行回收。