2013-02-19 18 views
7

Korzystam z backrestu java RESTful na GlassFish. Do tego dołączony jest frontend HTML5/JS, który mogę umieścić w projekcie webapp (a następnie dołączyć backend jako zależność) lub uruchomić na serwerze internetowym IIS w innej lokalizacji. CORS nie stanowi problemu. Cokolwiek rozwiązuje ten następujący problem:ThreadLocal Singleton

Sytuacja:

  1. Użytkownik1 loguje się i ścieżka bazy danych jest ustawiony na 'db/user1 /'
  2. user1 wstawia 'wartość 1' do bazy
  3. kłody użytkownik2 na i ścieżka bazy danych jest ustawiony na „db/użytkownik2 /”
  4. User1 próbuje usunąć „wartość 1” z bazy

User1 nie byłoby można usunąć wartość 1 z db/user1, ponieważ ścieżka do bazy danych została zmieniona na db/user2 i nie ma wartości 1 w tej bazie danych.

public class DataAccess{ 
    private static DataAccess dataaccess; 
    private String databasepath; 

    public static DataAccess getInstance() { 
     if (dataaccess == null) { 
      dataaccess = new DataAccess(); 
     } 
    } 
} 

Jak mogę zmodyfikować metodę getInstance() tak, że działa jako pojedyncza, ale tylko wewnątrz wątku tego użytkownika? Widziałem coś, co nazywa się wątkowo-lokalny, ale nie do końca to rozumiem, czy to może być rozwiązanie?

Każda pomoc jest z pewnością doceniana.

+0

Zadajesz 9 pytań i akceptujesz 0. Popraw to. – gaborsch

+0

jak mogę zaakceptować odpowiedź? –

+0

Przeczytaj ten rozdział w FAQ, są nawet zrzuty ekranu: http://stackoverflow.com/faq#howtoask – gaborsch

Odpowiedz

9

Ty mógłby użyć klasy ThreadLocal we wzór fabryki:

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(); 
    } 
} 

Będzie to jednak spowodować przeciek pamięci. Więc trzeba użyć Servlet Filter aby ustawić wartość na początku wniosku, a następnie usunąć go na końcu, niektóre jak:

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

Gdy masz class który implementuje Filter dodasz go do web.xml zatem :

<!--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 strona daje przykład filtra i jego przekształceń.
A twój DataAccess wyglądałby następująco:

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(); 
    } 
} 

Bądź niezwykle ostrożny z ThreadLocal jak to jest prawdopodobnie główną przyczyną wycieków pamięci w Javie. Dzięki serwerom sieciowym, które mają pule wątków, możesz uzyskać jeszcze poważniejsze błędy, jeśli ich nie wyczyścisz.

+0

+1, chciałem napisać to samo, ale byłeś szybszy :) – gaborsch

+1

The Szybkość odpowiedzi na SO zawsze mnie zadziwiła ... –

+2

Zauważ, że 'ThreadLocal's nie działają, jeśli używasz czegoś specjalnego, np. asynchroniczne EJB, Komety/Kontynuacje, ponieważ zastąpią działający wątek innym. – gaborsch

0

Wygląda że ThreadLocal powinno pomóc w przypadku użytkowej:

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

Ta klasa zawiera zmienne wątku lokalnego. Zmienne te różnią się od normalnych odpowiedników wartością tym, że każdy wątek, który uzyskuje dostęp do jednego (za pomocą metody get lub set), ma własną, niezależnie zainicjowaną kopię zmiennej .