2011-12-21 9 views
0

私はキャッシュプロバイダとして使用されるクラスを作成しました。マップ、タイムスタンプ付きのマップエントリを使用し、たびにクリーンアップを実行するスレッドを生成します。このクラスは、Webアプリケーションで使用されます。このWebアプリケーションにはPOSTに30秒かかるという問題がありました。問題を解決してこの問題を解決しました。このスレッドコードのどこにエラーがありますか?

私はこのクラスのエラーを見つけるために最善を尽くしましたが、できません。ここで私を助けてください。 ユーザークラスは、ユーザーを説明するPOJOの一種です。

public class UserStore implements Thread.UncaughtExceptionHandler { 
private static volatile UserStore instance; 
private static Thread cleanUpThread; 
private static Map<String, TimeStampedToken<User>> tokenMap = new HashMap<String, TimeStampedToken<User>>(); 
public static UserStore getInstance() { 
    if (instance == null) { 
     synchronized(UserStore.class) { 
      if (instance == null) { 
       instance = new UserStore(); 
       cleanUpThread = new Thread(new CleanUpWorker()); 
       cleanUpThread.setUncaughtExceptionHandler(instance); 
       cleanUpThread.start(); 
      } 
     } 
    } 
    return instance; 
} 
public void uncaughtException(Thread thread, Throwable throwable) { 
    if (throwable instanceof ThreadDeath) { 
     cleanUpThread = new Thread(new CleanUpWorker()); 
     cleanUpThread.setUncaughtExceptionHandler(this); 
     cleanUpThread.start(); 
     throw (ThreadDeath)throwable; 
    } 

} 
private static class CleanUpWorker implements Runnable { 
    private static final long CLEANUP_CYCLE_MS = 300000; 
    private static final long OBJECT_LIVE_TIME = 299900; 
    public void run() { 
     long sleepRemaining; 
     long sleepStart = System.currentTimeMillis(); 
     sleepRemaining = CLEANUP_CYCLE_MS; 
     while (true) { 
      try { 
       sleepStart = System.currentTimeMillis(); 
       Thread.sleep(sleepRemaining); 
       cleanUp(); 
       sleepRemaining = CLEANUP_CYCLE_MS; 
      } catch (InterruptedException e) { 
       sleepRemaining = System.currentTimeMillis() - sleepStart; 
      } 
     } 
    } 
    private void cleanUp() { 
     Long currentTime = System.currentTimeMillis(); 
     synchronized(tokenMap) { 
      for (String user : tokenMap.keySet()) { 
       TimeStampedToken<User> tok = tokenMap.get(user); 
       if (tok.accessed + OBJECT_LIVE_TIME < currentTime) { 
        tokenMap.remove(user); 
       } 
      } 
     } 
    } 

} 
public void addToken(User tok) { 
    synchronized(tokenMap) { 
     tokenMap.put(tok.getUserId(), new TimeStampedToken<User>(tok)); 
    } 
} 
public User getToken(String userId) { 
    synchronized(tokenMap) { 
     TimeStampedToken<User> user = tokenMap.get(userId); 
     if (user != null) { 
      user.accessed = System.currentTimeMillis(); 
      return user.payload; 
     } else { 
      return null; 
     } 

    } 
} 
private static class TimeStampedToken<E> { 
    public TimeStampedToken(E payload) { 
     this.payload = payload; 
    } 
    public long accessed = System.currentTimeMillis(); 
    public E payload; 
} 
} 
+2

問題はキャッシュクラスの機能とまったく同じですか?それは間違って(機能的に)動作しますか?または、あなたが望むよりも遅く動作します(POSTに時間がかかりすぎます)?もしそうなら、どのメソッド呼び出しに時間がかかりますか? – ArjunShankar

+1

スレッドを停止するよう特に指示された場合にのみ、スレッドを再起動するのはなぜですか? –

+0

有効期限のあるキャッシュを実装しようとしているようです。これを実装する方がはるかに簡単な方法がありますが、これを既に行っているライブラリを使用することもできます。 –

答えて

1

ここに私がアプローチします。マルチスレッドコードでは、シンプルさがしばしば最も効果的なアプローチです。

(のLinkedHashMapの三番目のパラメータtrueは、この地図の上にイテレータがアクセスではなく、挿入の順序の順序に従うことを意味します)

public enum UserStore { 
    ; 

    interface User { 
     String getUserId(); 
    } 

    // a LRU cache with a timestamp. 
    private static final Map<String, TimeStampedToken<User>> tokenMap = new LinkedHashMap<String, TimeStampedToken<User>>(16, 0.7f, true); 
    private static final long OBJECT_LIVE_TIME = 299900; 

    public static synchronized void addToken(User tok) { 
     final long now = System.currentTimeMillis(); 
     // clean up as we go 
     for (Iterator<Map.Entry<String, TimeStampedToken<User>>> iter = tokenMap.entrySet().iterator(); iter.hasNext();) { 
      final Map.Entry<String, TimeStampedToken<User>> next = iter.next(); 
      if (next.getValue().accessed + OBJECT_LIVE_TIME >= now) 
       // the map is ordered by access time so there are no more to clean up. 
       break; 
      iter.remove(); 
     } 
     // add a new entry 
     tokenMap.put(tok.getUserId(), new TimeStampedToken<User>(tok, now)); 
    } 

    public static synchronized User getToken(String userId) { 
     final long now = System.currentTimeMillis(); 
     TimeStampedToken<User> user = tokenMap.get(userId); 
     if (user == null) 
      return null; 

     user.accessed = now; 
     return user.payload; 
    } 

    static class TimeStampedToken<E> { 
     long accessed; 
     final E payload; 

     TimeStampedToken(E payload, long now) { 
      this.payload = payload; 
      accessed = now; 
     } 
    } 
} 
0

この行は、私には奇妙に見える...

sleepRemaining = System.currentTimeMillis() - sleepStart; (のSystem.currentTimeMillis() - - sleepStart)

...確かにそれは...

sleepRemaining = CLEANUP_CYCLE_MSする必要があります。

関連する問題