測試SpringMVC可能出現的線程安全問題


SpringMVC的Controller默認是單例的,對於同一個Controller而言,在整個web生命周期內只有一個對象。如果在Controller里寫了一個成員變量,這個變量是對所有線程可見的。

@Slf4j
@Controller
public class TestController {

    private List<String> list = new ArrayList<>();
  
    @RequestMapping(method = RequestMethod.GET, value = "/test")
    public ModelAndView test(Model model) {
        list.add(this.hashCode() + "");
        ModelAndView modelAndView = new ModelAndView("test");
        modelAndView.addObject("name", list.hashCode() + "--" +list.size());
        return modelAndView;
    }
}

頁面模板如下

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>
</head>
<body>
Hello ${name}
</body>
</html>



前后兩次請求list的size在發生變化說明兩次請求操作的是同一個list對象。由於list在添加對象后hashCode也會發生變化,所以兩次請求后的list的hashCode也發生了變化。

如果將Controller設置為原型模式,則每次請求都會new一個Controller的對象,此時不會出現線程安全問題。

@Slf4j
@Scope("prototype")
@Controller
public class TestController {
//······
}


此時雖然可能避免上述的線程安全問題,但是jvm必須為每次請求創建新的對象,在請求完成之后銷毀對象,這必然會增加系統的性能開銷。

附:ArrayList計算hashCode的源碼

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM