靜態內部類實現單例模式以及不需要顯式使用鎖的原因

先說結論:

靜態內部類實現單例模式,是藉助了類加載器加載類的特性實現的,類加載器在加載類時使用了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中了,就不繼續往下走了.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章