单例模式
单例模式就是说只有一个实例,是一种创建型的模式,并且她自己负责创建自己的对象,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象,类是私有的构造方法,向外提供一个实例访问方法,利用内部类创建单例可以实现较高性能的单例模式创建方式
代码清单
package com.zc.study.order.config;
public class SingletonConfig {
private SingletonConfig(){
//这是一个单例配置类私有构造方法........
}
private static class SingletonConfigHolder{
//这是一个静态内部类,用于创建单例实例
private static SingletonConfig configInstance = new SingletonConfig();
}
public static SingletonConfig configInstance(){
//向外提供SingletonConfig实例
return SingletonConfigHolder.configInstance;
}
}
原理
内部类是静态化的,在类加载时就已经创建了实例,在整个运行期都是单例的,顾而是单例的,但是问题来了,你会问,如果是多线程调用了configInstance()方法,线程是安全的,这就涉及到类加载机制了。我们知道,类不是一开始就在内存中的,而是由类加载器加载进内存中的,ClassLoader.loadClass(“class”);
/**
* Loads the class with the specified <a href="#name">binary name</a>.
* This method searches for classes in the same manner as the {@link
* #loadClass(String, boolean)} method. It is invoked by the Java virtual
* machine to resolve class references. Invoking this method is equivalent
* to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
* false)</tt>}.
*
* @param name
* The <a href="#name">binary name</a> of the class
*
* @return The resulting <tt>Class</tt> object
*
* @throws ClassNotFoundException
* If the class was not found
*/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
在loadClass()方法中,调用了又调用了loadClass(name, false)方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
而在loadClass(String name, boolean resolve)方法中加了synchronized关键字,故而类加载是线程安全的,所以这就是在public static SingletonConfig configInstance(){}方法中没有加synchronized同步关键字但还是线程安全的原因;大家知道synchronized是悲观锁,configInstance()方法没加synchronized同步关键字,所以就不存在争抢的问题,顾而解决了synchronized性能的问题