2016年3月8日 星期二

synchronized、initial & Destroy、三種變數 (Servlet 三)

※synchronized

如果沒有同步,需要注意有可能用戶端同時傳的問題


int i;
    
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter out = resp.getWriter();
    synchronized (this) {
        this.i++;
        try {
            Thread.sleep(2500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        out.println("a=" + i);
    }
}

※先將synchronized註解,然後開啟兩個瀏覽器,因為設定停止2.5秒,所以假設瀏覽器1得到1,瀏覽器得到2,
然後按完瀏覽器1時,在2.5秒之內按下瀏覽器2,會發現3不見了,兩個都是4



※initial & Destroy


@Override
public void init() throws ServletException {
    try (BufferedReader in = new BufferedReader(new FileReader("xxx"))) {
        i = Integer.parseInt(in.readLine());
    } catch (RuntimeException | IOException e) {
        i = 0;
    }
}
    
@Override
public void destroy() {
    try (PrintWriter out = new PrintWriter(new FileWriter("xxx"))) {
        out.println(i);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
    
int i;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter out = resp.getWriter();
    // synchronized (this) {
    this.i++;
    // try {
    // Thread.sleep(2500);
    // } catch (InterruptedException e) {
    // e.printStackTrace();
    // }
    out.println("a=" + i);
    // }
}

※doGet和synchronized一樣,多init()和destroy(),xxx檔案前面沒有c:\之類的路徑,預設會放在eclipse.exe的地方

※第一次進來因為還沒有xxx檔案,所以會exception,就給它0

※server關閉時,就會存起來,起動時才去抓

※注意Eclipse有兩個按鈕很像,如下:

正常關閉是按Servers的紅鈕(Stop the server),但如果是按Console的紅鈕(Terminate)或者是按Eclipse右上角的╳,那就不會執行destroy(),所以如果突然斷電也是一樣
預設destroy是沒有執行任何東西,所以如果都不覆寫,按哪個就沒有關係



※三種變數

HelloServlet.java

public class HelloServlet extends HttpServlet {
    static int classI = 0;
    int i = 0;
    static Map<HelloServlet, HelloServlet> mapInstances = new HashMap<>();
    static List<HelloServlet> listInstances = new ArrayList<>();
    static Set<HelloServlet> setInstances = new HashSet<>();
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain; charset=UTF-8");
        PrintWriter out = resp.getWriter();
    
        i++;
        out.println("實體變數=" + i);
    
        mapInstances.put(this, this);
        out.println("Map實體=" + mapInstances.size());
    
        setInstances.add(this);
        out.println("Set實體=" + setInstances.size());
    
        listInstances.add(this);
        out.println("List實體=" + listInstances.size());
        classI++;
        out.println("靜態變數=" + classI);
    }
}



web.xml

<servlet>
    <servlet-name>ooo</servlet-name>
    <servlet-class>controller.HelloServlet</servlet-class>
</servlet>
    
<servlet-mapping>
    <servlet-name>ooo</servlet-name>
    <url-pattern>/xxx</url-pattern>
</servlet-mapping>
    
<servlet>
    <servlet-name>aaa</servlet-name>
    <servlet-class>controller.HelloServlet</servlet-class>
</servlet>
    
<servlet-mapping>
    <servlet-name>aaa</servlet-name>
    <url-pattern>/ooo</url-pattern>
</servlet-mapping>

※結果參考:
實體變數=34
Map實體=1
Set實體=1
List實體=34
靜態變數=34

※只開一個瀏覽器或者開多個瀏覽器,但url最後都給xxx,結果就是34那三行一直變,Map實體和Set實體永遠都是1,因為Map的key和Set不可重覆

※另開一個瀏覽器,這次url最後給ooo,就會發現Map實體和Set實體是2了,而實體變數會從1開始,List實體和靜態變數是xxx和ooo的加總

※這個測試可以了解有幾個實體在run(Map實體和Set實體),每一個實體run了幾次(實體變數),全部的實體run了幾次(List實體、靜態變數)

※注意:我用3.0的@WebServlet(urlPatterns = { "/xxx", "/ooo" }),發現我給ooo和xxx,但Map實體和Set實體永遠都是1,可能設計的人認為既然一樣,就都給同一個實體吧!
又或者是版本問題,我用的是tomcat8(Servlet 3.1)

沒有留言:

張貼留言