-1

我只是从 servlet 和线程开始。最终实例变量是线程安全的,CopyOnArrayList 也是如此。为什么以下代码不是线程安全的(它是最终的 + 我使用了 CopyOnArrayList)?

@WebServlet("/index.html")
public class CatServlet extends HttpServlet {
    private final static long serialVersionUID = 1L;
    private final static String VIEW = "/WEB-INF/JSP/index.jsp";
    **private final CopyOnWriteArrayList <Cat> l = new CopyOnWriteArrayList<>();**

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        l.add(new Cat("Dean", 7));
        l.add(new Cat("Sam", 7));
        l.add(new Cat("Pixie", 0));
        request.setAttribute("catList", l);
        request.getRequestDispatcher(VIEW).forward(request, response);
    }

JSP代码:

<c:forEach var="cat" items="${catList}" >
    <li>${cat.name}</li>
</c:forEach>

首先我得到 3 个 Cat 实例。刷新时我得到 6,然后是 9、12,等等。为什么?当我在 doGet 方法中声明 CopyOnWriteArrayList 或使用简单数组时,不会出现此问题。我不明白它背后的逻辑:最终实例变量和 CopyOnWriteArrayList 应该是线程安全的。谢谢大家澄清这一点。

4

2 回答 2

3

自从您在doGet方法中添加它们以来,每次刷新页面时,您都会在列表中添加 3 个元素。

如果您在doGet方法中声明列表,则每次调用该方法时都会将其删除。

这里不涉及线程安全。

于 2016-02-03T10:13:55.743 回答
1

它是CopyOnWriteArrayList,不是EraseOnWriteArrayListCopyOnWriteArrayList每次写入时都会创建一个新副本,以便现有的迭代器继续在旧版本上运行。每次调用 doGet 时都不会删除该列表,因此它只是添加到末尾。每次添加新的Cat.

于 2016-02-03T10:20:05.267 回答