单例模式
Posted CoderBuff
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。
单例模式,顾名思义,在程序运行时有且仅有一个实例存在。最常见的一个应用场景就是网站访问量的计数器,试想如果允许创建多个实例,那还怎么计数,这个时候就得创建有且仅有的一个实例了。如何防止程序创建多个实例呢?首先就是不能直接new。不能new那就是要将构造函数实例化,那怎么来创建实例呢?我们还是从代码着手。
1 package day_5_singleton; 2 3 /** 4 * 单例 5 * @author turbo 6 * 7 * 2016年9月8日 8 */ 9 public class Singleton { 10 private static Singleton instance; 11 12 private Singleton(){ 13 } 14 15 public static Singleton GetInstance(){ 16 if (instance == null){ 17 instance = new Singleton(); 18 } 19 20 return instance; 21 } 22 }
1 package day_5_singleton; 2 3 /** 4 * @author turbo 5 * 6 * 2016年9月8日 7 */ 8 public class Main { 9 10 /** 11 * @param args 12 */ 13 public static void main(String[] args) { 14 Singleton singleton = Singleton.GetInstance(); 15 } 16 17 }
这就是单例模式的实现,看着好像挺简单的。它和传统的工具类有什么区别呢?一般的工具类也会将构造函数设为private,但是工具类不保存状态,仅提供一些静态方法或静态属性让你使用,而单例类是有状态的。
上面是针对单线程,单线程不会出现多个实例的情况,但是在多线程里就有可能会出现创建多个实例了。
不信我们来看。
首先,我们用单线程的方式来创建两个实例,看他们实际上是不是一个实例。
Singleton singleton1 = Singleton.GetInstance(); Singleton singleton2 = Singleton.GetInstance(); System.out.println(singleton1.hashCode()); System.out.println(singleton2.hashCode());
程序输出:
两个实例的hash值一样,说明他们是同一个实例。
我们再来看多线程的结果是怎样的,首先创建一个线程,在线程里实例化对象并输出hash值。
1 package day_5_singleton; 2 3 /** 4 * 多线程实例化单例类 5 * @author turbo 6 * 7 * 2016年9月8日 8 */ 9 public class ThreadTest implements Runnable { 10 11 /* (non-Javadoc) 12 * @see java.lang.Runnable#run() 13 */ 14 @Override 15 public void run() { 16 Singleton singleton = Singleton.GetInstance(); 17 System.out.println(singleton.hashCode()); 18 } 19 20 }
测试代码:
Thread singleton1 = new Thread(new ThreadTest()); Thread singleton2 = new Thread(new ThreadTest()); singleton1.start(); singleton2.start();
输出结果:
输出结果为两个实例的hash值确实不一样,说明确实创建了两个不同的实例。怎么办呢?加锁。对临界区共享资源的访问进行互斥访问,当一个线程进入临界区时,加锁,另一个线程进入临界区时则等待直到该对象被释放。
修改单例类。
1 package day_5_singleton; 2 3 /** 4 * 单例 5 * 6 * @author turbo 7 * 8 * 2016年9月8日 9 */ 10 public class Singleton { 11 private static Singleton instance; 12 13 private Singleton() { 14 } 15 16 public static synchronized Singleton GetInstance() { //synchronized关键字 17 18 if (instance == null) { 19 instance = new Singleton(); 20 } 21 22 return instance; 23 } 24 }
仅需对构造实例的方法添加synchronized关键字即可。
测试代码不变,看结果会发现两个线程创建的两个实例的hash值一样,说明它们是同一个实例。这样我们不管是在单线程还是多线程,所创建的这个单例类在程序里确实有且仅有一个。
我们其实可以继续引申synchronized关键字是什么,在方法上加和在给一个程序段加有什么区别?这会在以后开设一个多线程专栏来系统的介绍一下Java多线程。
以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章