单例模式概念及特点
java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例(应用比较少,不做介绍)三种。
单例模式有一下特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
饿汉式单例模式二(枚举实现):
单例对象 占用资源少,不需要延时加载:
枚举式好与 饿汉式
单例对象 占用资源大,需要延时加载:
静态内部类式好于懒汉式
java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例(应用比较少,不做介绍)三种。
单例模式有一下特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉式单例模式一(方法加锁):
package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 上午10:11:01
* 单例模式--懒汉式
* 优点:实现了简单的懒加载,真正用的时候才加载。
* 缺点:方法同步,调用效率稍低
*/
public class Singleton03 {
private static Singleton03 singleton03;
private Singleton03(){
}
public static synchronized Singleton03 getInstance(){
if (singleton03==null){
singleton03=new Singleton03();
}
return singleton03;
}
}
懒汉式单例模式二(双重检测锁机制):
package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 上午10:27:50
* 双重检测锁机制的懒汉式
* 优点:将同步内容下放到if内部,提高了执行效率,不必每次获取对象时进行同步。
* 缺点:由于编译器优化和JVM底层内部模型原因,偶尔会出问题,不建议使用。JDK5.0以后版本若instance为volatile则可行
*
* 因为这里的同步只需在第一次创建实例时才同步,一旦创建成功,以后获取实例时就不需要同获取锁了)
* 但在Java中行不通,因为同步块外面的if (instance == null)可能看到已存在,但不完整的实例。
* JDK5.0以后版本若instance为volatile则可行
*/
public class Singleton04 {
//private static Singleton04 singleton04;
private volatile static Singleton04 singleton04;
private Singleton04(){
}
public static Singleton04 getInstance(){
if(singleton04==null){
synchronized (Singleton04.class) {
if(singleton04==null){
singleton04=new Singleton04();
}
}
}
return singleton04;
}
}
为什么用volatile可以保证线程安全参考:
懒汉式单例模式三(静态内部类的方式):package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 上午10:46:40
* 静态内部类方式 实现懒汉式单例
* 优点:并发高效调用和延时加载的优势。
* 外部类没有static属性,则不会像俄汉式那样立即加载对象。
* 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。
* 因为instance是static final 类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证线程安全性。
*
*/
public class Singleton05 {
private Singleton05(){
}
public static class SingletonInstance{
private static final Singleton05 SINGLETON05 =new Singleton05();
}
public static Singleton05 getInstance(){
return SingletonInstance.SINGLETON05;
}
}
饿汉式单例模式一(静态常量实现):
package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 上午10:03:35
* 最简单的单例模式 饿汉式
*
* 优点:static,此时不会设计多个线程对象访问该对象的问题。变量会在类加载时初始化线程安全,调用效率高
* 缺点:无法实现延迟加载,如果是加载本类,而没有使用,则会造成资源浪费。
*/
public class Singleton01 {
private static final Singleton01 singleton01=new Singleton01();
//私有化构造方法
private Singleton01() {
}
//提供公有的获取实例的方法
public static Singleton01 getInstance(){
return singleton01;
}
}
饿汉式单例模式二(枚举实现):
package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 上午10:37:48
* 枚举实现饿汉式单例模式
* 优点:1、 自由序列化;2、 保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量);3、 线程安全;
* 缺点:无延时加载
*/
public enum Singleton02 {
INSTANCE;
public void sayHi(){
System.out.println("我是枚举类型的单例");
}
}
测试效率:
package cn.gof.singleton;
/**
* @author zhaopan
* @date 2016年10月21日 下午4:57:02
*
*/
import java.util.concurrent.CountDownLatch;
/**
* 测试多线程环境下五种创建单例模式的效率
* @author liguodong
*
*/
public class ClientTest {
public static void main(String[] args) throws InterruptedException {
long start = System.nanoTime();
int threadNum = 10;
long sum=0;
final CountDownLatch count = new CountDownLatch(threadNum);
int[] ins=new int[10];
for(int j=0;j<100;j++) {
for(int i=0;i<10;i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<1000000;i++)
{
/**
* 饿汉式
*/
// Object o = Singleton01.getInstance(); //普通饿汉式118755558---143202450
//Object o = Singleton02.INSTANCE;//枚举式的111872193---163903002 大部分是11-13
/**
* 懒汉式
*/
//Singleton03 instance = Singleton03.getInstance(); //方法加同步关键字2126685034
//Singleton04 instance2 = Singleton04.getInstance();//将方法内部加同步464849105
//Object o = Singleton05.getInstance(); //内部类的方式 118638630--134209601
}
count.countDown();
}
}).start();
}
count.await();//main线程阻塞,直到计数器变为0,才会继续往下执行。
long end = System.nanoTime();
sum=sum+end-start;
}
System.out.println("总耗时:"+(sum/100));
}
}
比较两种模式?
单例对象 占用资源少,不需要延时加载:
枚举式好与 饿汉式
单例对象 占用资源大,需要延时加载:
静态内部类式好于懒汉式