目录
应用场景:
要点:
常见的形式:
饿汉式:直接创建对象,不存在线程安全问题
1、直接实例化饿汉式(简洁直观)
2、枚举式(最简洁)
3、静态代码块饿汉式(适用复杂实例化)*
懒汉式:延迟创建对象
1、线程不安全(适用于单线程)
2、线程安全(适用于多线程)
3、静态内部类形式(适用于多线程)
应用场景:
单例模式可以解决一个需要全局使用的类进行频繁的创建和销毁,节省开销。
单例应用场景:
1.Windows的任务管理器,只能打开一个任务管理器。
2.Windows系统的回收站。
3.网站的计数器,通过单例模式可以很好实现。
4.应用程序的日志应用,一般都何用单例模式实现,这是由于系统一般共用一个日志。
5.数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
6.多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
要点:
1、某个类只能有一个实例
==>私有化构造器
2、它必须自行创建这个实例
==>含有一个该类的静态变量来保存这个唯一的实例
3、它必须向整个系统提供这个实例
==>对外提供获取该类的方式(1)直接暴露(2)用静态变量的get方法获取
常见的形式:
饿汉式:直接创建对象,不存在线程安全问题
1、直接实例化饿汉式(简洁直观)
package singleton;
/**
* 饿汉式,先造对象,不管你需不需要,都会创建
(1)私有化构造器
(2)自行创建,并用静态变量保存
(3)向外提供这个实例
(4)强调这是一个单例可以用final修饰(不可更改变为常量)
* @author YAN
*/
public class Singleton01 {
//1、私有化静态不可变的对象
public static final Singleton01 instance =new Singleton01();
//2、私有化构造器
private Singleton01(){
}
public static void main(String[] args) {
Singleton01 s1 = Singleton01.instance;
Singleton01 s11 = Singleton01.instance;
System.out.println(s1==s11);
}
}
2、枚举式(最简洁)
package singleton;
/**jdk1.5枚举类型,表示该类型的对象是有限的几个
我们可以限定为一个,就成了单例(与singleton01效果一样)
* 枚举方式最简洁
* @author YAN
*/
public enum Singleton02 {
instance;
public static void main(String[] args) {
Singleton02 s2 = Singleton02.instance;
Singleton02 s22 = Singleton02.instance;
System.out.println(s2==s22);
}
}
3、静态代码块饿汉式(适用复杂实例化)*
如创建对象的形参是properties文件中的value值时
package singleton;
import java.io.IOException;
import java.util.Properties;
public class Singleton03 {
public static final Singleton03 instance;
private String info;
static{
Properties pro = new Properties();
try {
pro.load(Singleton03.class.getClassLoader().getResourceAsStream("single.properties"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance = new Singleton03(pro.getProperty("info"));
}
private Singleton03(String info){
this.info=info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public static Singleton03 getInstance() {
return instance;
}
@Override
public String toString() {
return "Singleton03 [info=" + info + "]";
}
public static void main(String[] args) {
Singleton03 s3 = Singleton03.instance;
Singleton03 s33 = Singleton03.instance;
System.out.println(s3);
System.out.println(s33);
}
}
结果如下
懒汉式:延迟创建对象
1、线程不安全(适用于单线程)
package singleton;
/**
* 懒汉式,最后创建对象
* (1)私有化构造器
* (2)提供一个静态变量保存这个唯一的实例
* (3)提供一个静态方法获取这个实例对象
* @author YAN
*/
public class Singleton04 {
//不用public修饰防止直接调用instance为空
private static Singleton04 instance;
private Singleton04(){
}
public static Singleton04 getInstance(){
if(instance==null){
instance = new Singleton04();
}
return instance;
}
public static void main(String[] args) {
Singleton04 s4 = Singleton04.getInstance();
Singleton04 s44 = Singleton04.getInstance();
System.out.println(s4==s44);
}
}
2、线程安全(适用于多线程)
package singleton;
/**
* 懒汉式,最后创建对象
(1)私有化构造器
(2)提供一个静态变量保存这个唯一的实例
(3)提供一个静态方法获取这个实例对象
*
* @author YAN
*/
public class Singleton05 {
// 不用public修饰防止直接调用instance为空
static Singleton05 instance;
private Singleton05() {
}
public static Singleton05 getInstance() {
if (instance == null) {// 为了提高效率
synchronized (Singleton05.class) {// 加锁后线程安全
if (instance == null) {
instance = new Singleton05();
}
}
}
return instance;
}
public static void main(String[] args) {
Singleton05 s5 = Singleton05.getInstance();
Singleton05 s55 = Singleton05.getInstance();
System.out.println(s5 == s55);
}
}
3、静态内部类形式(适用于多线程)
package singleton;
/**
* 静态内部类不会随着外部类的加载和初始化而被初始化的
* 它是单独进行初始化的
* 因为是在内部类加载时才会被创建所以线程是安全的
* @author YAN
*
*/
public class Singleton06 {
private Singleton06(){
}
//当内部类加载和初始化才会创建对象
public static class inner {
private static final Singleton06 instance = new Singleton06();
}
//当调用getInstance()方法时内部类会初始化创建对象
public static Singleton06 getInstance(){
return inner.instance;
}
public static void main(String[] args) {
Singleton06 s6 = Singleton06.getInstance();
Singleton06 s66 = Singleton06.getInstance();
System.out.println(s6==s66);
}
}
总结: 一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测