Image

Imagekamen_jahr wrote in Imageru_java

Непятничное;-) thread-safe servlets & Servlet 2.4 vs. Servlet 3.0

Имея траблы с многопоточностью в веб приложении решил проанализировать задачу на простейшем примере. Для этого я взял "сложнейший";-))) сорц примера (обычного счетчика, объявленного private ) не thread-safe сервлета с из этой древней статьи Write thread-safe servlets и хтмл-код оттуда же (в котором череи ифрейм стартуют сервлеты три раза). Однако следющая фигня обнаружена была:
Если я декларирую параметры в web.xml (servlet-name,url-pattern....)  то после старта сервлета и вызова хтмл-страницы...счетчик во фреймах увеличивается правильно почему то, хотя в ява-коде нет синхронизации то
frame1
com.threadtest.ThrdTstServlet1@367c3:
Counter Test= 0
Counter Test=1
Counter Test= 2
Counter Test= 3
Counter Test= 4
Counter Test=5
Counter Test= 6
Counter Test= 7
Counter Test= 8
Counter Test= 9
frame2
com.threadtest.ThrdTstServlet1@367c3:
Counter Test= 10
Counter Test=11
Counter Test= 12
Counter Test= 13
Counter Test= 14
Counter Test=15
Counter Test= 16
Counter Test= 17
Counter Test= 18
Counter Test=19

frame3
com.threadtest.ThrdTstServlet1@367c3:
Counter Test= 20
Counter Test=21
Counter Test= 22
Counter Test= 23
Counter Test= 24
Counter Test=25
Counter Test= 26
Counter Test= 27
Counter Test= 28
Counter Test=29

Если же я закоменнтирую параметры в display-name, servlet-mapping и оставлю только "шапку" , где версия объявлена и welcome-file-list. А в ява-коде пропишу @WebServlet("/tsttrd1"), то несинхронизированность проявит себя (как и описано было в статье)

frame1
com.threadtest.ThrdTstServlet1@11a67b9:
Counter Test= 0
Counter Test=2
Counter Test= 4
Counter Test= 6
Counter Test= 8
Counter Test=10
Counter Test= 12
Counter Test= 14
Counter Test= 17
Counter Test=19

frame2
com.threadtest.ThrdTstServlet1@11a67b9:
Counter Test= 0
Counter Test=2
Counter Test= 3
Counter Test= 5
Counter Test= 7
Counter Test=9
Counter Test= 11
Counter Test= 13
Counter Test= 15
Counter Test=17

frame3
com.threadtest.ThrdTstServlet1@11a67b9:
Counter Test= 20
Counter Test=21
Counter Test= 22
Counter Test= 23
Counter Test= 24
Counter Test=25
Counter Test= 26
Counter Test= 27
Counter Test= 28
Counter Test=29
Почему так????
P.S под катами коды
package com.threadtest;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
//import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ThrdTstServlet
 *
http://www.javaworld.com/javaworld/jw-07-2004/jw-0712-threadsafe.html?page=3
We create simultaneous requests by using HTML frames; each frame's source is the same servlet: see {@WEB_default.html file with calls of this servlet.

 */
//@WebServlet("/tsttrd1")
public class ThrdTstServlet1 extends HttpServlet {
    private static final long serialVersionUID = 1L;

    //A variable that is NOT thread-safe!
    private int counter = 0;

    //    private String mutex = "";// mutual exclusion

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ThrdTstServlet1() {
        super();

        System.out.println("ThrdTstServlet constructor");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {

        super.init(config);
        System.out.println("ThrdTstServlet init(ServletConfig config) called");
    }

    @Override
    public void init() throws ServletException {

        super.init();
        System.out.println("ThrdTstServlet init() called");
    }

    /**
     * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
     */
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        //        super.service(request, response);

        System.out.println("ThrdTstServlet service(HttpServletRequest request, HttpServletResponse response) called");
        //        synchronized (mutex) {
        //A variable that IS thread-safe!
        //         int counter = 0;
        response.getWriter().println("");
        response.getWriter().println(this + ":
");
        for (int c = 0; c < 10; c++) {
            response.getWriter().println("Counter Test= " + counter + "
");
//            System.out.println("Counter Test= " + counter);
            try {
                Thread.currentThread().sleep((long) ( Math.random() * 1000) );
                counter++;
            } catch (InterruptedException exc) {
            }
        }
        response.getWriter().println("");
        //        }
    }


}

...

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
   AtestThreadSafe

  
      
      

       ThrdTstServlet1
       ThrdTstServlet1
       com.threadtest.ThrdTstServlet1
  

  
       ThrdTstServlet1
       /tsttrd1
  


  
       index.html
       index.htm
       index.jsp
       default.html
       default.htm
       default.jsp
  




<HTML>
  <BODY>
    <TABLE>
      <TR>
        <TD>
          <IFRAME src="/AtestThreadSafe/tsttrd1"
                  name="servlet1"
                  height="100%">
          </IFRAME>
        </TD>
      </TR>
      <TR>
        <TD>
          <IFRAME src="/AtestThreadSafe/tsttrd1"
                  name="servlet2"
                  height="100%">
          </IFRAME>
        </TD>
      </TR>
      <TR>
        <TD>
          <IFRAME src="/AtestThreadSafe/tsttrd1"
                  name="servlet3"
                  height="200%">
          </IFRAME>
        </TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>


Upd.0
Уточнения про индокод и браузеры:
Во-первых, в изначальную копипасту пробралась ашибко (arteamon заметил): "Кстати, что за адская жесть
Thread.sleep((long) Math.random() * 1000);Math.random() приведенный к long будет же всегда 0. Индусский прогрев процессора?
"
Сей фейл пофиксен скобками Thread.sleep((long) ( Math.random() * 1000) );
И вот что обнаружилось после фикса:  появились задержки вызовов сервлета.
Если я вызываю страницу с ифреймами в ИЕ 8м (или движке его из под среды разработки екслипс) - то все как и положено: счетчики не синхронные.
Однако, если я стартую ту же страницу с ифреймами в файрефоксе или хроме - то счетчики синхронные. Использовал томкат 7.0.28 +windows (xp / 7).