ThreadLocal Singleton

Pie*_*Jan 7 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"

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

任何帮助肯定是值得赞赏的.

Bor*_*der 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这会导致内存泄漏.因此,您需要使用Servlet过滤器在请求开始时设置值,然后在最后删除它,例如:

   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();
      }
   }
Run Code Online (Sandbox Code Playgroud)

一旦你有一个class实现过滤器,你可以将它添加到你的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>
Run Code Online (Sandbox Code Playgroud)

页面提供了过滤器及其映射的示例.
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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,如果使用任何特殊的东西,例如异步EJB,Comets/Continuations,则ThreadLocal不起作用,因为它们将用另一个替换正在运行的Thread. (2认同)