ThreadLocal Singleton

时间:2013-02-19 13:57:45

标签: java singleton thread-local

我在GlassFish上运行RESTful java后端。附加一个HTML5 / JS前端,我可以将其放入webapp项目(然后将后端包含为依赖项),或者在不同位置的IIS Web服务器上运行。 CORS不是问题。无论如何解决以下问题:

情况:

  1. User1登录,数据库路径设置为'db / user1 /'
  2. User1将“值1”插入数据库
  3. User2登录,数据库路径设置为“db / user2 /”
  4. User1尝试从数据库中删除“值1”
  5. User1将无法从db / user1中删除值1,因为数据库路径已更改为db / user2且该数据库中没有值1。

    public class DataAccess{
        private static DataAccess dataaccess;
        private String databasepath;
    
        public static DataAccess getInstance() {
            if (dataaccess == null) {
                dataaccess = new DataAccess();
            }
        }
    }
    

    如何修改getInstance()方法以使其充当单例,但仅在该用户的线程内?我看到了一些名为threadlocal但没有完全理解它的东西,这可能是一个解决方案吗?

    任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:10)

可以在工厂模式中使用ThreadLocal类:

public class DataAccess{
    private static ThreadLocal<DataAccess> THREAD_LOCAL = new ThreadLocal() {
     @Override
     protected DataAccess initialValue() {
             return new DataAccess();
     }
    };
    private String databasepath;

    public static DataAccess getInstance() {
      return THREAD_LOCAL.get();
    }
}
但是,这会导致内存泄漏。因此,您需要使用Servlet Filter在请求开头设置值,然后在结尾处删除它,例如:

   public void doFilter(ServletRequest request,
      ServletResponse response, FilterChain chain) 
      throws IOException, ServletException {
      DataAccess.set(new DataAccess("SomeValue"));
      try {
        chain.doFilter(request, response);
      } finally {
        DataAcess.remove();
      }
   }

一旦你有class实施Filter,就可以将其添加到web.xml

<!--Filter for adding in dataccess objects-->
<filter>
    <filter-name>DataccessFilter</filter-name>
    <filter-class>my.package.DataccessFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>DataccessFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

This页面提供了过滤器及其映射的示例 你的DataAccess看起来像是:

public class DataAccess{
    private static ThreadLocal<DataAccess> THREAD_LOCAL = new ThreadLocal();
    private String databasepath;

    public DataAcess(final String databasepath) {
      this.databasepath = databasepath;
    }

    public static DataAccess getInstance() {
      return THREAD_LOCAL.get();
    }
    public static void set(final DataAccess dataAccess) {
      THREAD_LOCAL.set(dataAccess);
    }
    public static void remove() {
      THREAD_LOCAL.remove();
    }
}

非常小心ThreadLocal因为它可能是Java中内存泄漏的头号原因。对于具有线程池的Web服务器,如果不正确清理它们,可能会遇到更严重的错误。

答案 1 :(得分:0)

看起来ThreadLocal应该帮助您处理用例:

http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

  

此类提供线程局部变量。这些变量不同   来自他们的正常对应者,每个访问一个的线程   (通过其get或set方法)有自己的,独立初始化   变量的副本。