单例设计模式
1基本介绍
(1)定义
在整个软件系统中,确保某一个类有且只有一个实例对象,有且只有一个取得该实例对象的静态方法。
(2)单例模式的8种方式
饿汉式(静态常量)、饿汉式(静态代码块)、双重检查、静态内部类、枚举、懒汉式(线程不安全)、懒汉式(线程安全,同步方法)、懒汉式(线程安全,同步代码块)
a.饿汉式(静态常量)
public class singletonTest01 {
public static void main(String[] args) {
SingleTon singleTon1 =SingleTon.getInstance();
SingleTon singleTon2 =SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//饿汉式(静态变量)
//优点:类加载的时候就完成实例化,避免了线程同步问题
//缺点:没有达到懒加载lazy loading的效果,若从未使用过instance这个实例,则会造成内存的浪费
//个人认为:假使可能浪费内存,那么是否可以使用if语句判断(某些条件下未使用时,就删除此instance)
class SingleTon{
//1.构造器私有化,外部不能new
private SingleTon(){
}
//2.本类内部创建对象实例
private final static SingleTon instance = new SingleTon();
//3.提供公有的静态方法,返回对象实例
public static SingleTon getInstance(){
return instance;
}
}
b.饿汉式(静态代码块)
与饿汉式(静态变量)只是代码有所改变,优缺点相同!
public class singletonTest02 {
public static void main(String[] args) {
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//饿汉式(静态变量)
//优点:类加载的时候就完成实例化,避免了线程同步问题
//缺点:没有达到懒加载lazy loading的效果,若从未使用过instance这个实例,则会造成内存的浪费
//个人认为:假使可能浪费内存,那么是否可以使用if语句判断(某些条件下未使用时,就删除此instance)
class SingleTon {
//1.构造器私有化,外部不能new
private SingleTon() {
}
//2.本类内部定义一个静态的SingleTon变量
private static SingleTon instance;
static {//在静态代码中创建实例对象
instance = new SingleTon();
}
//3.提供公有的静态方法,返回对象实例
public static SingleTon getInstance() {
return instance;
}
}
c.懒汉式1(线程不安全,实际开发中不可使用!)
public class singletonTest03 {
public static void main(String[] args) {
System.out.println("懒汉式1,线程不安全!");
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//懒汉式
class SingleTon{
private static SingleTon instance;
private SingleTon(){}
//提供静态的公有方法;当使用到该方法时才去创建instance
public static SingleTon getInstance(){
if(instance==null){
instance = new SingleTon();
}
return instance;
}
}
d.懒汉式2(效率太低,不使用)
public class singletonTest04 {
public static void main(String[] args) {
System.out.println("懒汉式2,线程安全!");
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//懒汉式(线程安全,同步方法)
class SingleTon{
private static SingleTon instance;
private SingleTon(){}
//提供静态的公有方法;加入同步处理代码,解决线程不安全的问题,同时保证了效率
public static synchronized SingleTon getInstance(){
if(instance==null){
instance = new SingleTon();
}
return instance;
}
e.懒汉式(“线程安全”,不能用。错误的!)
解决不了线程安全问题,判空时,可能已经多个线程进来了。
public class singletonTest05 {
public static void main(String[] args) {
System.out.println("懒汉式3,线程安全!");
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//懒汉式(线程安全,同步方法)
class SingleTon{
private static SingleTon instance;
private SingleTon(){}
//提供静态的公有方法;加入同步处理代码,解决线程不安全的 问题
public static SingleTon getInstance(){
if(instance==null){
synchronized(SingleTon.class){
instance = new SingleTon();
}
}
return instance;
}
}
f.双重检查(推荐使用,可以解决线程安全,可以解决效率问题!)
优缺点说明:
定义instance变量时使用关键字volatile!
public class singletonTest06 {
public static void main(String[] args) {
System.out.println("双重检查,线程安全!");
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//双重检查(线程安全,同步方法)
class SingleTon {
private static volatile SingleTon instance;
private SingleTon() {
}
//提供静态的公有方法;加入双重检查代码,解决线程不安全的 问题,解决懒加载问题
public static synchronized SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
if (instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
}
g.静态内部类
1.外部类SingleTon进行类加载时,静态内部类不会进行类加载,保证了懒加载问题
2.当调用getInstance()方法时,才会实例化静态内部类,才会使用到静态内部类的静态变量SingleTonInstance.INSTANCE,这时!才会加载静态内部类SingleTonInstance,JVM在类加载时,是线程安全的;故而保证了线程安全。
public class singletonTest07 {
public static void main(String[] args) {
System.out.println("使用静态内部类完成单例设计模式");
SingleTon singleTon1 = SingleTon.getInstance();
SingleTon singleTon2 = SingleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
System.out.println("singleTon1.hashCode()=" + singleTon1.hashCode());
System.out.println("singleTon2.hashCode()=" + singleTon2.hashCode());
}
}
//静态内部类完成单例设计模式,推荐使用!
class SingleTon {
private static volatile SingleTon instance;
//有一个静态属性为SingleTon的静态内部类SingleTonInstance
private static class SingleTonInstance {
private static final SingleTon INSTANCE = new SingleTon();
}
//构造器私有化
private SingleTon() {
}
//提供静态的公有方法,直接返回静态内部类的静态变量SingleTonInstance.INSTANCE
public static synchronized SingleTon getInstance() {
return SingleTonInstance.INSTANCE;
}
}
h.枚举
public class singletonTest08 {
public static void main(String[] args) {
SingleTon instance =SingleTon.INSTANCE;
SingleTon instance2 =SingleTon.INSTANCE;
System.out.println(instance == instance2);
System.out.println( "instance.hashCode()=" + instance.hashCode()+ "; "+"instance2.hashCode()=" + instance2.hashCode());
instance.sayHello();
}
}
//使用枚举可以实现单例设计模式,推荐使用
enum SingleTon{
INSTANCE;
public void sayHello(){
System.out.println("Hello,dear boy!");
}
}
2.在JDK中使用(源码分析)
java.lang.Runtime就是经典的单例设计模式的应用场景。