静态内部类实现单例模式以及不需要显式使用锁的原因

    技术2022-07-17  80

    先说结论:

    静态内部类实现单例模式,是借助了类加载器加载类的特性实现的,类加载器在加载类时使用了synchronized关键字.

    单例模式代码:

    public class SingletonDemo { public static void main(String[] args) { SingletonDemo sd1 = getInstance(); SingletonDemo sd2 = getInstance(); System.out.println(sd1.equals(sd2)); } private SingletonDemo(){}; private static class SingletonHolder{ private static SingletonDemo INSTANCE = new SingletonDemo(); } public static SingletonDemo getInstance(){ return SingletonHolder.INSTANCE; } }

    输出为:

    true

    首次执行getInstance()方法,调用SingletonHolder中的静态属性INSTANCE时,触发SingletonHolder类的加载,而new SingletonDemo()也会被执行,且只被执行一次.

    在多线程环境下是如何实现同步的呢?这就要看ClassLoader类的源码了:

    public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); }

    经过调试,可以确定的是,程序先进入了上面这个方法.但是点击F7进入的却不是下面这个方法:

    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 PerfCounter.getParentDelegationTime().addTime(t1 - t0); PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }

    进入的是ClassLoaders.AppClassLoader类中的loadClass()方法:

    @Override protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException { // for compatibility reasons, say where restricted package list has // been updated to list API packages in the unnamed module. SecurityManager sm = System.getSecurityManager(); if (sm != null) { int i = cn.lastIndexOf('.'); if (i != -1) { sm.checkPackageAccess(cn.substring(0, i)); } } return super.loadClass(cn, resolve); }

    执行super.loadClass(),进入了BuiltinClassLoader类中的loadClass()方法:

    @Override protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException { Class<?> c = loadClassOrNull(cn, resolve); if (c == null) throw new ClassNotFoundException(cn); return c; }

    执行loadClassOrNull()方法,然后进入同一个类中的loadClassOrNull()方法:

    protected Class<?> loadClassOrNull(String cn, boolean resolve) { synchronized (getClassLoadingLock(cn)) { // check if already loaded Class<?> c = findLoadedClass(cn); if (c == null) { // find the candidate module for this class LoadedModule loadedModule = findLoadedModule(cn); if (loadedModule != null) { // package is in a module BuiltinClassLoader loader = loadedModule.loader(); if (loader == this) { if (VM.isModuleSystemInited()) { c = findClassInModuleOrNull(loadedModule, cn); } } else { // delegate to the other loader c = loader.loadClassOrNull(cn); } } else { // check parent if (parent != null) { c = parent.loadClassOrNull(cn); } // check class path if (c == null && hasClassPath() && VM.isModuleSystemInited()) { c = findClassOnClassPathOrNull(cn); } } } if (resolve && c != null) resolveClass(c); return c; } }

    终于出现了,synchronized关键字!

    调用链很长,但是都是在synchronized中了,就不继续往下走了.

    Processed: 0.042, SQL: 9