一 单例模式的作用:
节省内存和计算 保证结果正确,方便管理
二.使用场景
1.无状态的工具类:比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象即可。
2.全局信息类:比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象A上,有的却记录在对象B上,这时候我们就让这个类成为单例。
三单例模式的8种写法
1.:饿汉式(静态常量)
package singleton;
/**
* 描述:饿汉式(静态常量)
*/
public class Singleton1 {
//类装载时完成实例化避免线程同步问题
private final static Singleton1 INSTANCE = new Singleton1();
private Singleton1() {
}
public static Singleton1 getInstance() {
return INSTANCE;
}
}
2.饿汉式(静态代码块)
package singleton;
/**
* Description: 饿汉式(静态代码块)
*
* @Auther: FengGuoXing
* @Date: 19-10-3 11:52
*/
public class Singleton2 {
private final static Singleton2 INSTANCE;
static {
INSTANCE = new Singleton2();
}
private Singleton2(){
}
public static Singleton2 getInstance(){
return INSTANCE;
}
}
- 懒汉式(线程不安全)(不可用)
package singleton;
/**
* Description: 懒汉式(线程不安全)(不可用)
*
* @Auther: FengGuoXing
* @Date: 19-10-3 11:55
*/
public class Singleton3 {
private static Singleton3 instance;
private Singleton3() {
}
public static Singleton3 getInstance() {
//多线程到达这一步式,有可能同时进行判断,然后创建多个实例
if (instance == null) {
instance = new Singleton3();
}
return instance;
}
}
4懒汉式(线程安全)(不推荐)
package singleton;
/**
* Description: 懒汉式(线程安全)(不推荐)
*
* @Auther: FengGuoXing
* @Date: 19-10-3 12:01
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {
}
public synchronized static Singleton4 getInstance() {
//效率太低
if (instance == null) {
instance = new Singleton4();
}
return instance;
}
}
5 懒汉式(线程不安全)(不推荐)
package singleton;
/**
* Description: 懒汉式(线程不安全)(不推荐)
*
* @Auther: FengGuoXing
* @Date: 19-10-3 12:03
*/
public class Singleton5 {
private static Singleton5 instance;
private Singleton5() {
}
public static Singleton5 getInstance() {
if (instance == null) {
//同样是线程不安全的:当两个线程同时到达这块代码的时候,虽然只能有一个线程拿到锁,
// 然后创建实例,但创建后此线程会释放锁,另一个线程同样会再次拿到货,再次创建实例
synchronized (Singleton5.class) {
instance = new Singleton5();
}
}
return instance;
}
}
$6双重检查 :线程安全,延迟加载,效率较高,面试推荐
package singleton;
/**
* Description: 双重检查 :线程安全,延迟加载,效率较高,面试推荐
*
* @Auther: FengGuoXing
* @Date: 19-10-3 12:06
*/
public class Singleton6 {
//volatile作用是防止重排序:实例对象是先创建一个空的对象,然后调用构造方法,最后将实例赋值到引用上,但是CPU和编译器可能进行重排序这三个顺序有可能发生颠倒,可能会使其他线程调用时,产生空指针问题
private volatile static Singleton6 instance;
private Singleton6() {
}
public static Singleton6 getInstance() {
if (instance == null) {
synchronized (Singleton6.class) {
//当多个线程进入到此处时,加入双重检验,即使其他线程拿到了锁,通过判断发现已经创建了实例,所以不会再次创建.
if (instance == null) {
instance = new Singleton6();
}
}
}
return instance;
}
}
7静态内部类(线程安全和懒加载) 可用
package singleton;
/**
* Description: 静态内部类(线程安全和懒加载) 可用
*
* @Auther: FengGuoXing
* @Date: 19-10-3 12:29
*/
public class Singleton7 {
private Singleton7() {
}
private static class SingletonInstance {
private final static Singleton7 INSTANCE = new Singleton7();
}
public static Singleton7 getInstance(){
return SingletonInstance.INSTANCE;
}
}
$8枚举单例:可用生产实践中
优点
- 写法简单
- 线程安全有保障
- 避免反序列化破坏单例
package singleton;
/**
* Description: 枚举单例:可用生产实践中
* Joshua Bloch大神在《Effective Java》中明确表达过的观点:“使用枚举实现单例的方法虽然还没有广泛采用,但是单元素的枚举类型已经
* 成为实现Singleton的最佳方法。
* @Auther: FengGuoXing
* @Date: 19-10-3 12:37
*/
public enum Singleton8 {
INSTANCE;
public void whatever() {
}
}
四各种写法的使用场景
◆最好的方法是利用枚举,因为还可以防止反序列化重新创建新的对象;
◆非线程同步的方法不能使用;
◆如果程序-开始要加载的资源太多,那么就应该使用懒加载;
◆饿汉式如果是对象的创建需要配置文件就不适用。
◆懒加载虽然好,但是静态内部类这种方式会引入编程复杂性