2009-03-05 30 views
46

Ngoài ra, đối tượng đang được đặt phải là chủ đề an toàn để đảm bảo rằng chúng tôi biết trạng thái của đối tượng được lưu trữ trong phiên được biết đến.Có phải chuỗi chủ đề an toàn của HttpSession được đặt/nhận thuộc tính hoạt động an toàn của chủ đề không?

Ngoài ra, tôi đã được đọc trên web mà một số đề nghị sử dụng:

synchronized(session) { 
    session.setAttribute("abc", "abc"); 
} 

Đây có phải là một đề nghị hợp lệ?

Trả lời

34

Không, chúng không phải là chủ đề an toàn, theo IBM - Java theory and practice: Are all stateful Web applications broken?. Bạn cần phải đồng bộ hóa.

How HttpSession is not thread safe từ Java Ranch cũng có thể hữu ích.

+3

Phải đọc liên kết! ++ – cherouvim

+0

Tại sao bạn muốn đồng bộ hóa chúng? Có một phiên cho mỗi khách hàng và khách hàng là đơn luồng không? – OscarRyz

+1

@Oscar Reyes: Một khách hàng có thể đưa ra nhiều yêu cầu đồng thời. Ví dụ: CTRL + CLICK (trên firefox) như điên trên logo stackoverflow. – cherouvim

4

số Và kể từ khi bạn không muốn cùng một khách hàng (với phiên) để được làm yêu cầu đồng thời, bạn nên serialize những yêu cầu như AbstractController làm trong Spring MVC

+1

Tôi thích ví dụ này nhưng vẫn còn một chút bối rối về cách tôi sẽ sử dụng điều này cho ứng dụng của mình. –

2

Trong một số cách khác nhau, điều này phụ thuộc vào bạn thiết kế của khách hàng.

Bạn có cơ hội, trong thiết kế web của mình, để một khách hàng duy nhất có nhiều yêu cầu đồng thời xuất sắc bằng cách sử dụng cùng một phiên HTTP không? Điều này có vẻ khó thực hiện trừ khi bạn kết nối một phiên HTTP duy nhất với nhiều ổ cắm. (aka, AJAX) Ngắn làm điều này, một truy cập HTTP của khách hàng nhất định sẽ được đơn luồng như xa như máy chủ là có liên quan, có nghĩa là một phiên duy nhất là hiệu quả Thread an toàn.

Đồng bộ hóa đối tượng phiên của bạn sẽ làm cho ứng dụng an toàn hơn so với các thay đổi trong tương lai khiến ứng dụng web của bạn có khả năng có nhiều yêu cầu đồng thời, vì vậy không phải là một ý tưởng tồi. Trong việc triển khai Java hiện đại, việc đồng bộ hóa không có chi phí lớn mà trước đó được liên kết với nó, đặc biệt khi đồng bộ hóa thường không được kiểm soát. Nếu ứng dụng của bạn sử dụng AJAX, điều này ngụ ý rằng bạn mong đợi nhiều yêu cầu đồng thời trên máy bay đến máy chủ web của bạn, thì việc đồng bộ hóa là phải.

+0

Tôi chỉ đang nghĩ về việc vô hiệu hóa "synchronizeOnSession" cho các yêu cầu ajax để tăng tốc mọi thứ (yêu cầu ajax đang thực hiện cái khác, không song song). Vì vậy, nó là một lớn không có không? Tôi nghĩ rằng nó là an toàn cho ajax vì dòng công việc thường được kiểm soát trên bên javascript anyway. – serg

0

Phiên không phải là chủ đề an toàn và không phải phương thức nhận được không được đảm bảo là luồng an toàn. Nói chung trong một thùng chứa servlet, bạn nên giả sử là trong một môi trường đa luồng và không có công cụ nào được cung cấp là an toàn.

Điều này cũng phù hợp với các đối tượng bạn lưu trữ trong phiên. Bản thân phiên sẽ không thao tác đối tượng đã lưu nhưng bạn có thể lấy đối tượng trong chuỗi khác và cố gắng thao tác nó. Bạn có thể kiểm tra mã của riêng mình để xem liệu điều kiện chủng tộc có khả thi hay không.

Ví dụ mã bạn đã đăng hợp lệ, nhưng vấn đề có thể tồn tại vượt quá phạm vi giới hạn của ví dụ của bạn. Nó đảm bảo không có điều kiện trong khi thiết lập cho phiên, nhưng không có gì ngăn cản một thread khác ghi đè lên tập hợp. Nếu mã trong yêu cầu của bạn phụ thuộc vào giá trị còn lại không thay đổi, bạn vẫn có thể gặp sự cố.

61

Servlet 2.5 spec:

Nhiều servlets thực hiện yêu cầu đề có thể tiếp cận tích cực để các cùng một đối tượng session cùng lúc. Vùng chứa phải đảm bảo rằng thao tác dữ liệu nội bộ cấu trúc đại diện cho phiên các thuộc tính được thực hiện theo cách an toàn . Nhà phát triển có trách nhiệm đối với threadafe quyền truy cập vào các đối tượng thuộc tính .Điều này sẽ bảo vệ bộ sưu tập thuộc tính bên trong đối tượng Http1ession HttpSession từ truy cập đồng thời , loại bỏ cơ hội cho một ứng dụng khiến bộ sưu tập bị hỏng.

Đây là an toàn:

// guaranteed by the spec to be safe 
request.getSession().setAttribute("foo", 1); 

Đây là không an toàn:

HttpSession session = request.getSession(); 
Integer n = (Integer) session.getAttribute("foo"); 
// not thread safe 
// another thread might be have got stale value between get and set 
session.setAttribute("foo", (n == null) ? 1 : n + 1); 

Đây là không đảm bảo an toàn:

// no guarantee that same instance will be returned, 
// nor that session will lock on "this" 
HttpSession session = request.getSession(); 
synchronized (session) { 
    Integer n = (Integer) session.getAttribute("foo"); 
    session.setAttribute("foo", (n == null) ? 1 : n + 1); 
} 

Tôi đã thấy cách tiếp cận cuối cùng này được ủng hộ (bao gồm trong các cuốn sách J2EE), nhưng nó không được đảm bảo để làm việc theo đặc tả Servlet. Bạn có thể use the session ID to create a mutex, nhưng phải có cách tiếp cận tốt hơn.

+0

Cố gắng hiểu những gì "Các container phải đảm bảo rằng thao tác của các cấu trúc dữ liệu nội bộ đại diện cho các thuộc tính phiên được thực hiện một cách an toàn" có nghĩa là. Nó không có nghĩa là một container như 'tomcat' là nghĩa vụ phải đảm bảo rằng các phương thức getAttribute và setAttribute là thread an toàn? Ngoài ra, tại sao phương pháp cuối cùng không được đảm bảo để hoạt động? – letronje

+0

@letronje - điều này có nghĩa là các cuộc gọi riêng lẻ đến getAttribute/setAttribute phải là luồng an toàn, nhưng không có đảm bảo giao dịch nào được thực hiện cho servlet. Vì vậy, việc sử dụng đồng thời cùng một phiên có thể dẫn đến trạng thái không nhất quán trừ khi nhà phát triển servlet bảo vệ chống lại điều đó. – McDowell

+1

@letronje - cách tiếp cận cuối cùng yêu cầu phiên làm việc đồng bộ hóa trên 'this'. Tức là, có một chữ ký như 'public syncrhonized void setAttribute ...' hoặc '... setAttribute (String s, Object o) {đồng bộ (this) ...'. Thông số kỹ thuật không yêu cầu điều này. Một số thùng chứa servlet làm điều này, nhưng không có sự bảo đảm nào - cách container bảo vệ trạng thái bên trong là một chi tiết thực hiện. – McDowell

1

Chúng không phải, nhưng hầu hết thời gian, khách hàng của bạn sẽ chỉ truy cập chúng bằng một chuỗi duy nhất.

Các khách hàng khác nhau sẽ có các chủ đề khác nhau và mỗi chủ đề sẽ có Phiên riêng của mình.

Như Eddie chỉ ra, một tình huống mà bạn có thể đối mặt với hai chuỗi truy cập cùng một phiên là hai cuộc gọi ajax đang cố sửa đổi cùng một thuộc tính phiên. Nếu không, bạn sẽ không gặp vấn đề gì.

Các vấn đề liên quan