カテゴリ: Jakarta EE 更新日: 2026/02/02

JakartaEE サーブレットのスレッドセーフとフィルタ利用時の注意点を徹底解説!初心者でも安心の入門ガイド

Jakarta EE サーブレットのスレッドセーフとフィルタ利用時の注意点
Jakarta EE サーブレットのスレッドセーフとフィルタ利用時の注意点

先生と生徒の会話形式で理解しよう

生徒

「先生、JakartaEEのサーブレットって複数のユーザーが同時にアクセスしたらどうなるんですか?」

先生

「いい質問ですね。サーブレットはデフォルトでシングルトンとして動作するので、同じインスタンスに複数のスレッドが同時に入ってきます。つまりスレッドセーフを意識しないと予期しない不具合が起きるんです。」

生徒

「なるほど…。じゃあ、フィルタを使う場合も同じように気を付ける必要があるんですか?」

先生

「その通りです。サーブレットもフィルタもライフサイクルが似ているので、共通の注意点があるんです。具体的に見ていきましょう。」

1. JakartaEE サーブレットのスレッドセーフとは?

1. JakartaEE サーブレットのスレッドセーフとは?
1. JakartaEE サーブレットのスレッドセーフとは?

JakartaEE のサーブレットは、リクエストごとに新しいインスタンスが生成されるわけではなく、通常は一つのサーブレットインスタンスが再利用されます。そのため、同じサーブレットに対して同時に複数のユーザーがアクセスすると、複数のスレッドが並行して実行されることになります。これを「サーブレットのスレッドモデル」と呼びます。

もしサーブレット内でインスタンス変数を不用意に使うと、同時アクセスで変数が上書きされてしまい、データの整合性が失われる危険があります。これが「スレッドセーフでない状態」です。例えばログイン処理やセッション管理をインスタンス変数で持ってしまうと、ユーザーの情報が混ざってしまうケースが発生します。

2. サーブレットでスレッドセーフを確保する方法

2. サーブレットでスレッドセーフを確保する方法
2. サーブレットでスレッドセーフを確保する方法

サーブレットをスレッドセーフにするためには、次のポイントを守ることが大切です。

  • インスタンス変数を使わず、ローカル変数にデータを格納する
  • 必要な情報は HttpServletRequestHttpSession に保持する
  • 共有リソースを操作する場合は synchronized ブロックなどを用いて排他制御する

例えば次のコードは良くない例です。複数のユーザーが同時にアクセスすると message が上書きされてしまいます。


@WebServlet("/unsafe")
public class UnsafeServlet extends HttpServlet {
    private String message; // インスタンス変数に状態を持ってしまっている

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        message = "Hello " + req.getParameter("user");
        resp.getWriter().println(message);
    }
}

3. フィルタ利用時のスレッドセーフの注意点

3. フィルタ利用時のスレッドセーフの注意点
3. フィルタ利用時のスレッドセーフの注意点

JakartaEE の フィルタもサーブレットと同じようにシングルトンで管理されます。つまり、複数のリクエストが同時に同じフィルタインスタンスを通過するため、インスタンス変数の扱いには注意が必要です。

例えばログの記録やリクエストの検証などを行うフィルタはよく使われますが、状態を持たせると予期しない動作が起きます。ログの内容が別のユーザーに混ざることもあり得ます。


@WebFilter("/*")
public class UnsafeFilter implements Filter {
    private String user; // 危険なインスタンス変数

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        user = request.getParameter("user");
        System.out.println("User: " + user);
        chain.doFilter(request, response);
    }
}

このコードでは同時リクエスト時に user が上書きされ、ログに誤ったユーザー情報が出力される恐れがあります。解決策としては、必ずローカル変数を使うことが推奨されます。

4. フィルタで安全に状態を扱う方法

4. フィルタで安全に状態を扱う方法
4. フィルタで安全に状態を扱う方法

フィルタ内で必要な情報は、必ずメソッド内のローカル変数で保持しましょう。次の例のように書けば、同時リクエストでも安全に動作します。


@WebFilter("/*")
public class SafeFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String user = request.getParameter("user"); // ローカル変数で保持
        System.out.println("User: " + user);
        chain.doFilter(request, response);
    }
}

このようにフィルタでスレッドセーフを守ることで、ログや認証処理を安全に行うことができます。

5. サーブレットとフィルタで共通する設計上のポイント

5. サーブレットとフィルタで共通する設計上のポイント
5. サーブレットとフィルタで共通する設計上のポイント

JakartaEE サーブレットとフィルタのスレッドセーフを意識する上で、次のような共通点を押さえておくと安全です。

  • インスタンス変数でリクエストごとの状態を持たない
  • スレッド間で共有する必要がある場合は適切な排他制御を行う
  • スレッドローカル(ThreadLocal)を使うことで、一時的なスレッドごとのデータ管理も可能
  • ステートレスな設計を心掛けると安全で保守性も高くなる

特に初心者は「インスタンス変数を極力使わない」というルールを守るだけでも大きなトラブルを防げます。

6. 実務でよくあるスレッドセーフの落とし穴

6. 実務でよくあるスレッドセーフの落とし穴
6. 実務でよくあるスレッドセーフの落とし穴

実際の開発現場では、便利だからといってサーブレットやフィルタにキャッシュや一時的な値をインスタンス変数として持たせてしまうケースがよくあります。これがパフォーマンスの低下やデータの混在を引き起こす原因になります。

また、認証情報やユーザーIDなどをフィルタのインスタンス変数で持つと、セキュリティ事故につながることがあります。そのため、初心者はまず「状態を持たせない」ことを強く意識しましょう。

関連記事:
カテゴリの一覧へ
新着記事
New1
Play Framework
Play Frameworkでクッキーを守る!Secure属性とHttpOnly属性の設定方法を徹底解説
New2
Play Framework
マイクロサービス時代におけるPlay Frameworkの位置付けを徹底解説!初心者でもわかる最新Javaフレームワークの役割
New3
Play Framework
Play Frameworkとは?特徴と歴史を初心者向けにわかりやすく解説
New4
Jakarta EE
Jakarta EEのServletフィルタとは?仕組みと役割を初心者向けにやさしく解説
人気記事
No.1
Java&Spring記事人気No1
Jakarta EE
Jakarta EEとJava EEアプリの互換性を完全解説!移行で困らないための基礎知識
No.2
Java&Spring記事人気No2
Jakarta EE
Jakarta サーブレットのdoGetとdoPostの違いと使い分けを徹底解説!初心者でもわかるHTTPリクエスト処理
No.3
Java&Spring記事人気No3
Jakarta EE
Jakarta EEとは?Java EEからの移行の歴史をやさしく解説
No.4
Java&Spring記事人気No4
Jakarta EE
Jakarta EE JAX-RSインターセプタの仕組みを完全解説 初心者でも理解できるReaderInterceptorとWriterInterceptorの使い方
No.5
Java&Spring記事人気No5
Play Framework
Play Frameworkのセッション固定攻撃対策!Javaで安全なログイン機能を実装する方法
No.6
Java&Spring記事人気No6
Play Framework
Play Frameworkでセッション管理と認証を連携!Java初心者向けログイン実装ガイド
No.7
Java&Spring記事人気No7
Jakarta EE
Jakarta EEを支えるEclipse Foundationの役割とは?初心者向けにわかりやすく解説
No.8
Java&Spring記事人気No8
Jakarta EE
Jakarta EE JSON-PとJSON-Bの違いと役割を徹底解説 初心者でも理解できるJSON処理の基本