在多个自定义ClassLoad下的单例研究
2016-03-13 00:23
169 查看
在一次面试中被问到,如何在有多个不同的类加载器,并且这些类加载器的父加载器都不同,的情况下实现一个单例。
后来回家之后对这个问题进行了研究,现在将研究结果记录下来。
打开sun.misc.Launcher类,在下面的第15行代码说明在JVM启动之后,JVM中的第一个初始化的JAVA线程的上下文类加载器,被设置成了AppClassLoad的实例。
代码如下:
在Thread类的init方法中,下面的第45和47行代码,会将改Thread实例的上下文类加载器,设置为父线程的上下文类加载器。由上面可知该线程的上下文类加载器会被设置成了AppClassLoad的实例。
代码如下:
如果你的单例因为多个类加载器的问题变成了多例,可以利用JAVA线程的上下文类加载器,来统一单利类的类加载器,从而解决单例变多例的问题。
代码如下:
后来回家之后对这个问题进行了研究,现在将研究结果记录下来。
打开sun.misc.Launcher类,在下面的第15行代码说明在JVM启动之后,JVM中的第一个初始化的JAVA线程的上下文类加载器,被设置成了AppClassLoad的实例。
代码如下:
public Launcher() { Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader"); } try { this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader"); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if(var2 != null) { SecurityManager var3 = null; if(!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) { ; } } else { var3 = new SecurityManager(); } if(var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } }
在Thread类的init方法中,下面的第45和47行代码,会将改Thread实例的上下文类加载器,设置为父线程的上下文类加载器。由上面可知该线程的上下文类加载器会被设置成了AppClassLoad的实例。
代码如下:
private void init(ThreadGroup g, Runnable target, String name, long stackSize) { if (name == null) { throw new NullPointerException("name cannot be null"); } Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { /* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager what to do. */ if (security != null) { g = security.getThreadGroup(); } /* If the security doesn't have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? */ if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); this.name = name.toCharArray(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = AccessController.getContext(); this.target = target; setPriority(priority); if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }
如果你的单例因为多个类加载器的问题变成了多例,可以利用JAVA线程的上下文类加载器,来统一单利类的类加载器,从而解决单例变多例的问题。
代码如下:
public class RedisUtilReal { private static class RedisUtilHolder { private static volatile RedisUtilReal redisUtilReal; static { init(); } private static void init() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { Class<?> redisUtilRealClass = classLoader.loadClass(RedisUtilReal.class.getName()); RedisUtilHolder.redisUtilReal = (RedisUtilReal) redisUtilRealClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } if (RedisUtilHolder.redisUtilReal == null) { System.out.println("redis util init fail."); } else { System.out.println("redis util init success."); } } } protected RedisUtilReal() { } public static RedisUtilReal getInstance() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = RedisUtilReal.class.getClassLoader(); } try { classLoader.loadClass(RedisUtilReal.class.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } return RedisUtilHolder.redisUtilReal; }
相关文章推荐
- Java各个集合(Collection)的特性和用途
- java调用matlab程序
- BestCoder Round #75 1003 - King's Order
- WebAPI2使用AutoFac依赖注入完整解决方案。
- [leetcode] Longest Consecutive Sequence
- C++第1次实验—复习-函数T 1
- 为什么32位cpu只支持4G内存?
- iOS子线程更新UI的两种方法
- 微软
- House Robber III leetcode 动态规划
- AudioManger和AudioSystem的关系
- package com.skex.ttsdemo
- HDU Elevator
- 希尔排序
- 再谈缓存和Redis
- 二、Nginx变量
- Android—将Bitmap图片保存到SD卡目录下或者指定目录
- CodeForces337D(树形DP)
- Linux下搭建android环境
- Linux系统下以RPM方式如何安装mysql-5.7.9