场景描述:
1.为某软件做了一个扩展功能的插件,插件可以随时被加载或删除,而不影响软件本身的运行;
2.插件中定义了一个单例的类,也就是说,这个类的存在唯一一个静态对象,这个静态对象在插件被加载时生成;
3.这个单例类的构造器中启动了一个维护线程;
4.在第一次加载插件时,单例类的唯一静态对象被创建,调用构造器时启动了维护线程;
5.删除插件,插件的删除代码中关闭了之前开启的那个维护线程,但此时单例类的静态对象依旧存在;
6.再次加载插件,因为之前插件中的单例类对象依旧存在,所以不会调用单例类的构造器,也不会启动维护线程。如上描述,因为单例模式的原因,不能每次加载插件时都启动维护线程,要解决这个问题,只能每次都重启该软
件本身,但这不太实际,因为软件是必须一直运行的。所以问题归结到:
能不能在删除插件时销毁其单例类的静态对象?或者更宽泛些,怎样手工销毁静态对象?多线程单例模式静态对象

解决方案 »

  1.   

    额,在单例类里加个public方法把这个静态实例变量赋值为null是不是就行了
      

  2.   

    是啊,你关掉维护线程的同时,将单例对象=null
      

  3.   

    置null是一个办法。
    但是没解决根本性问题,因为类未被卸载。
    事实上类的卸载根本不由你控制。假设你改了一个BUG,类名没有变,
    你删除当前插件,然后马上安装新插件,
    结果往往是调来的还是老插件,因为原来的类没被卸载。
    通常解决的办法是用classloader,但这依赖与母程序的构架设计。
    情况往往是很复杂的。要实现或者学习热插件系统,
    可以参看OSGi规范,以及他的开源实现。
    eclipse就是这个构架。个人觉得,Hadson 也是一个比较好的热插件系统范例,
    可以看看Hudson源码。
      

  4.   

    类的卸载问题。楼上 +1这个没做过,不过据说一个类被“卸载”的条件是,加载它的 ClassLoader 被回收。一般 plugin 里的类需要“看到”软件里的类型,所以这个 ClassLoader 一般其 parent 为软件主体的 ClassLoader设计上要注意,软件主体中的任何类型是“看不到” plugin 那一层加载的类型的,所以软件主体中任何部分不能提到plugin那一层加载的类型。同一个程序下分级的ClassLoader有很多隐患,有些第三方的库因为自身的设计问题可能会“越级”加载类型而导致出错,比如 Jasper Report
      

  5.   

    简单的 null 掉那个单例的实例,并不能释放 plugin 加载的静态资源。并且也排除了依赖类的加载来又“安全”又“懒”的进行实例化的可能。
      

  6.   

    重新为你的插件写一个专职的ClassLoader,
    http://vivisidea.iteye.com/blog/662620
      

  7.   


    这个方法只适用于类似下面的Singleton实现方式:class Singleton {
    private static Singleton instance = null;  // 重点,此处不为null就不可用

    private Singleton() {
    System.out.println("Constructing a Singleton object.");
    }
    public static synchronized Singleton getInstance() {
    if (instance == null) {
    instance = new Singleton();
    }
    return instance;
    }
    public static synchronized void dstroyInstance() {
    if (instance != null) instance = null;
    }
    }
      

  8.   


    Good Idea. 但最终还是要把引用置为null吧?有可以直接调用的方法来显示unload一个class吗?
      

  9.   


    Good Idea. 但最终还是要把引用置为null吧?有可以直接调用的方法来显示unload一个class吗?
    这个不需要,判断两个类是否相等只有在这两个类是被同一个类加载器加载的情况下才有意义,假如两个不同的类加载器加载的是同一个class文件,那么这两个类也不相等,所以个人认为,当你的插件卸载之后再部署,前后运行的这两个单例类并不相等,因为他们的类加载器并不相等。
      

  10.   

    在单例类里加个public方法把这个静态实例变量赋值为null