单例模式
- 定义:程序运行时,在java虚拟机中只存在该类的一个实例对象。
- demo:
package mode;
public class SingleDemo {
// 创建SingleDemo单例对象
private static SingleDemo instance = new SingleDemo();
// 将构造方法设成私有的,这样该类就不会被实例化
private SingleDemo() {}
public static SingleDemo getInstance() {
return instance;
}
public void showMessage() {
System.out.println("这里是重要的信息");
}
}
class SingleAply{
public static void main(String[] args) {
SingleDemo singleDemo = SingleDemo.getInstance();
singleDemo.showMessage();
}
}
实现方式
懒汉式-线程不安全
懒汉式_线程不安全 | |
---|---|
优点 | 1.起到了延迟加载的效果 |
缺点 | 1.只能在单线程下使用 2.如果在多线程下,一个线程进入了if(single==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这是便会产生多个实例。所以多线程不可以使用 |
结论 | 在实际开发中,不要使用这种方式 |
public class LazyNotSafe {
private static LazyNotSafe instance;
private LazyNotSafe() {}
public LazyNotSafe getInstance() {
if (instance == null) {
instance = new LazyNotSafe();
}
return instance;
}
}
懒汉式-线程安全
懒汉式_线程安全 | |
---|---|
优点 | 1.解决了线程不安全问题 |
缺点 | 1.效率太低,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。 2.而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。 |
结论 | 在实际开发中,不要使用这种方式 |
public class LazySafe {
private static LazySafe instance;
private LazySafe() {}
public static synchronized LazySafe getInstance() {
if (instance == null) {
instance = new LazySafe();
}
return instance;
}
}
懒汉式-线程不安全同步代码块
懒汉式_同步代码块 | |
---|---|
优点 | 延迟加载 |
缺点 | 1.本意是对线程安全的懒汉式进行改进,因为其同步方法效率太低,改为同步产生的实例化代码块 2.线程不能同步。假如一个线程进入了if(instance==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例 注意:synchronized同步代码块中,当释放锁后,会继续向下执行 |
结论 | 在实际开发中,不能用这种方式 |
public class LazyNoSafePiece {
private static LazyNoSafePiece instance;
private LazyNoSafePiece() {}
public LazyNoSafePiece getInstance() {
if (instance == null) {
synchronized(LazyNoSafePiece.class) {
instance = new LazyNoSafePiece();
}
}
return instance;
}
}
饿汉式-静态变量/静态代码块
饿汉式_静态变量/静态代码块 | |
---|---|
优点 | 在类加载的时候完成了实例化,避免了线程同步问题。 |
缺点 | 在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从头到尾未使用过这个实例,则会造成内存的浪费 |
结论 | 这种单例模式可以使用,但可能会造成内存的浪费 |
class HungrySafe {
private static HungrySafe instance = new HungrySafe();
private HungrySafe() {}
public static HungrySafe getInstance() {
return instance;
}
}
class HungrySafe2 {
private static HungrySafe2 instance;
private HungrySafe2() {}
static {
instance = new HungrySafe2();
}
public static HungrySafe2 getInstance() {
return instance;
}
}
双重检查(推荐使用)
双重检查 | |
---|---|
优点 | 1.线程安全 2.延迟加载 3.效率较高 4.实例化代码只用执行一次,后面再次访问时,判断第一层if(xxx==null),直接return实例化对象,也避免的反复进行方法同步。 |
结论 | 在实际开发中,推荐使用 |
public class DoubleCheck {
private DoubleCheck doubleCheck;
private DoubleCheck() {}
public DoubleCheck getInstance() {
if (doubleCheck == null) {
synchronized(DoubleCheck.class) {
if (doubleCheck == null) {
doubleCheck = new DoubleCheck();
}
}
}
return doubleCheck;
}
}
静态内部类(推荐使用)
优势 | |
---|---|
如何保证实例时只有一个线程? 即如何保证线程安全? |
类的静态属性只会在第一次加载类的时候初始化,在类进行初始化时,别的线程是无法进入的,所以线程安全 |
如何实现延迟加载 | 利用静态内部类,不是在xxx类被装载时立即实例化,而是在调用getInstance方法时,才会装载xxx类,从而完成xxx类的实例化 |
public class InnerClass {
// volatile:一有修改就更新到主存中去
private static volatile InnerClass instance;
private InnerClass() {}
private static class InnerInstance {
private final static InnerClass instance = new InnerClass();
}
public static InnerClass getInstance() {
return InnerInstance.instance;
}
}