单例模式
简单介绍
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
一、懒汉式单例
package wbg; import com.Thr; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args) { ExecutorService ex= Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { ex.execute(new Runnable() { @Override public void run() { Boss boss=Boss.getInstance(); System.out.println(boss); } }); } } } class Boss { private Boss(){}; private static Boss boss=null; public static Boss getInstance() { if (boss == null) { boss = new Boss(); } return boss; } }
运行结果(多次运行)
Boos通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Boss的唯一实例只能通过getInstance()方法访问。
(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全
1、在getInstance方法上加同步
package wbg; import com.Thr; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args) { ExecutorService ex= Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { ex.execute(new Runnable() { @Override public void run() { Boss boss=Boss.getInstance(); System.out.println(boss); } }); } } } class Boss { private Boss(){}; private static Boss boss=null; public synchronized static Boss getInstance() { if (boss == null) { boss = new Boss(); } return boss; } }
运行结果
2、双重检查锁定
package wbg; import com.Thr; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args) { ExecutorService ex= Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { ex.execute(new Runnable() { @Override public void run() { Boss boss=Boss.getInstance(); System.out.println(boss); } }); } } } class Boss { private Boss(){}; private static Boss boss=null; public static Boss getInstance() { if (boss == null) { synchronized(Boss.class){ if (boss == null) { boss = new Boss(); } } } return boss; } }
运行结果
3、静态内部类
package wbg; import com.Thr; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test { public static void main(String[] args) { ExecutorService ex= Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { ex.execute(new Runnable() { @Override public void run() { Boss boss=Boss.getInstance(); System.out.println(boss); } }); } } } class Boss { static class LazyHolder{ private static final Boss inst=new Boss(); } private Boss(){}; public static final Boss getInstance(){ return LazyHolder.inst; } }
运行结果
这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。
详细:http://www.iteye.com/topic/652440
volatile关键字
package wbg; public class Boss { String name; String sex; Float money; //初始化一个静态变量 private static volatile Boss boss=null; //设置为私有 private Boss() { } //构造一个静态方法,通过它初始化或返还对象 public static Boss getBoss(){ //双重检查所机制 if(boss==null){ synchronized(Boss.class){ if(boss==null){ boss=new Boss(); } } } return boss; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Float getMoney() { return money; } public void setMoney(Float money) { this.money = money; } }