Поведение статических переменных в сервлете Java - PullRequest
8 голосов
/ 02 сентября 2010

Я занимаюсь разработкой Java-сервлета, который во время работы запускает различные методы объектов в новых потоках.Эти потоки должны обращаться к переменной, которая описывает конкретный экземпляр сервлета, скажем, jobId.По этой причине я объявил переменную jobId как статическую.Конструктор сервлета вычисляет это значение для каждого экземпляра сервлета (вызова).Я бродил, если сервлет вызывается несколько раз в одно и то же время, статическая переменная jobId распределяется между вызовами, что означает, что некоторые потоки получат неправильный jobId, или рассчитывается один раз для каждого вызова, такконкретный запущенный сервлет будет использовать jobId, рассчитанный для этого конкретного сервлета (именно так я и хочу, чтобы он работал).Есть идеи?Большое спасибо!

Ответы [ 4 ]

29 голосов
/ 02 сентября 2010

Сервлет создается только один раз при запуске веб-приложения и распределяется между всеми запросами.Статические или нет, каждая переменная класса / экземпляра будет разделена между всеми запросами / сессиями.Вы не хотели бы назначать им данные области запроса / сеанса.Скорее объявляйте / назначайте их как переменную methodlocal.Например,

public class MyServlet extends HttpServlet {
    private static Object thisIsNotThreadsafe;
    private Object thisIsAlsoNotThreadsafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadsafe;

        thisIsNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests.
        thisIsAlsoNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests.
        thisIsThreadsafe = request.getParameter("foo"); // Good.
    }
}

Существует устаревший и устаревший SingleThreadModel интерфейс, который вы можете использовать в своем сервлете для принудительного создания во время каждого запроса.Но это плохой дизайн и излишне дорогой.Именно поэтому он устарел.

См. Также:

2 голосов
/ 02 сентября 2010

Политика создания экземпляров для сервлетов не определена в спецификации сервлета (насколько я помню, в любом случае), но обычное поведение, по-видимому, заключается в создании только одного экземпляра на конфигурацию сервлета.Таким образом, в вашем случае каждый запрос будет использовать одну и ту же переменную.

На вашем месте я бы посоветовал отправить jobId в качестве параметра тем Runnable, с которыми вы запускаете потоки.Например, вместо этого:

public class HelloWorld extends HttpServlet {
    private static long jobId;
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        jobId = Long.parseLong(request.getParameter("jobid");
        new Thread(new Worker()).start();
    }

    static class Worker implements Runnable {
        @Override
        public void run() {
            doSomethingWith(jobId);
        }
    }

}

Рефакторинг статических переменных, таких как:

public class HelloWorld extends HttpServlet {
    // private static long jobId; -- delete, no longer needed
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        long jobId = Long.parseLong(request.getParameter("jobid"); // local variable
        new Thread(new Worker(jobId)).start(); // send jobId as parameter
    }

    static class Worker implements Runnable {
        private final long jobId; // non-static; every instance has one
        public Worker(long jobId) { // allow injection of jobId
            this.jobId = jobId;
        }
        @Override
        public void run() {
            doSomethingWith(jobId); // use instance variable instead of static
        }
    }

}

Легче читать, нет проблем с параллелизмом - чистый выигрыш.

2 голосов
/ 02 сентября 2010

Статические переменные являются общими. Статические переменные не принадлежат ни одному экземпляру, они доступны всем экземплярам класса. Когда вы используете конструктор, который используется для создания одного объекта (одного экземпляра класса), установка статической переменной в конструкторе, как правило, не имеет смысла, поскольку она выходит за рамки создаваемого вами объекта .

Что касается того, что сработает, вы можете поместить jobId в HttpSession, и тогда у каждого пользователя будет своя его копия.

2 голосов
/ 02 сентября 2010

static означает, что каждый экземпляр будет иметь доступ к одному и тому же значению.
Таким образом, каждый пользователь, подключенный к сервлету, будет иметь доступ к одному и тому же значению.Ваш jobId, вероятно, будет неправильным, когда 2 или более пользователей соединены вместе.

Вы должны получить свое собственное значение для каждого соединения и сохранить его где-нибудь еще.:

По той же теме:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...