2012-02-21 10 views
6

Tôi có một bean Spring đơn (phạm vi mặc định). Vì vậy, một ví dụ sẽ được sử dụng bởi nhiều chủ đề. Tuy nhiên, tôi hơi bối rối về vấn đề an toàn luồng, dường như tất cả các Spring bean đều an toàn nếu chúng không trạng thái, nhưng đậu của tôi không phải là không trạng thái, nó có các biến cá thể khác nhau được sử dụng bởi mỗi yêu cầu/các bộ điều khiển/lớp khác.Spring MVC Singleton thread safety?

Đây là sự khởi đầu của đậu singleton tôi:

public class PcrfSimulator { 

private final CustomGxSessionIdCacheImpl gxSessionIdCache = new CustomGxSessionIdCacheImpl(); 
private final PcrfRecord pcrfRec = new PcrfRecord(); 
private final ResponseConditions responseConditions = new ResponseConditions(); 

public CustomGxSessionIdCacheImpl getGxSessionIdCache() { 
    return gxSessionIdCache; 
} 

public ArrayList<Rule> getRules() { 
    return pcrfRec.getRules(); 
} 

Vì vậy, các lĩnh vực trên sẽ được truy cập bởi nhiều chủ đề - là nó đủ để đánh dấu các lĩnh vực này là dễ bay hơi, hoặc làm tôi phải đánh dấu những methods mà truy cập chúng (có rất nhiều trong không chỉ lớp này, nhưng bộ điều khiển khác/lớp học cũng) với đồng bộ và sử dụng chờ đợi/thông báo vv?

Rất cám ơn!

Trả lời

3

volatile không giúp ích gì. Nó chỉ đảm bảo rằng giá trị thực sự được cập nhật.

phương tiện dễ bay hơi (http://www.javamex.com/tutorials/synchronization_volatile.shtml):

  • Giá trị của biến này sẽ không bao giờ được lưu trữ thread-địa phương: tất cả đọc và viết di chúc đi thẳng đến "bộ nhớ chính";
  • Truy cập vào biến hoạt động như thể nó được đính kèm trong khối được đồng bộ hóa, được đồng bộ hóa trên chính nó.

Làm phương pháp đồng bộ sẽ chỉ giúp đỡ nếu kiểm soát dòng chảy của bạn không bao giờ thoát khỏi (bên ngoài) khối đồng bộ giữa ghi đầu tiên và đọc trước các biến dùng chung, và tất cả các biến dùng chung chỉ được truy cập trong khối đồng bộ sử dụng cùng một đối tượng khóa.

Vì vậy, giải pháp chung là ngăn các biến được chia sẻ trong trường hợp này. Một cách dễ dàng để làm cho lớp không thay đổi là sử dụng các biến cục bộ và các tham số phương thức thay vì các biến cá thể được chia sẻ.


Bạn đã viết "Đậu xuân là chỉ an toàn nếu chúng không quốc tịch, nhưng đậu của tôi không phải là quốc tịch". - Ok chủ đề đó được thảo luận trong đoạn trên.

Nhưng từ mã của bạn là đường nối rằng đây không phải là vấn đề! Các biến được đánh dấu bằng final để chúng không thay đổi. Nếu các trường của đối tượng đó hoạt động theo cùng một cách (không được cập nhật hoặc được bảo vệ đầy đủ đối với các vấn đề sửa đổi đồng thời), bạn không có biến chia sẻ có thể thay đổi. Đôi khi, điều này được gọi là "trạng thái vô hiệu hóa". Điều này có nghĩa là các giá trị không thay đổi. Vì vậy, đây không phải là vấn đề đối với đồng thời, (vì vấn đề đồng thời là về việc thay đổi các giá trị).

Cuối cùng: Bạn có thể sử dụng lớp không trạng thái hiệu quả này từ ví dụ trong các chủ đề khác nhau mà không có khối đồng bộ nếu các trường (PcrfRecord ...) có hiệu lực không trạng thái. (Nếu các trường PcrfRecord ... không phải là không quốc tịch thì lớp học PcrfSimulator không thể được gọi là không quốc tịch hiệu quả) - Nhưng điều này đã chú ý đến với Spring, nó là đồng bằng Java.

Btw: nếu biến của bạn là final bạn không cần phải đặt chúng volantile.

+0

Cảm ơn Ralph, nhưng cuối cùng không chỉ có nghĩa là chúng chỉ có thể được khởi tạo một lần? Tôi nói điều này bởi vì trong đoạn mã các biến cuối cùng được cập nhật như vậy: gxSessionIdCache.addIpAddress (gxSessionId, ipAddress) - thực sự chúng được cập nhật khi được chuyển thành tham số cho các phương thức không sử dụng trường cuối cùng - tức là doStuff (GxSessionIDCache gxSessionIdCache) {... } – Rory

+0

Tôi giả định rằng đối tượng "đằng sau" biến cuối cùng cũng "có hiệu lực không quốc tịch" – Ralph

+0

@Rory: Tôi đã mở rộng đoạn đó một chút, để làm cho nó rõ ràng. – Ralph

3

Bản thân Spring đảm bảo xuất bản đúng các hạt của bạn một khi đã được khởi tạo, tiêm, v.v. Điều này có nghĩa là bất kỳ chuỗi nào có tham chiếu đến bean đơn của bạn sẽ ít nhất thấy trạng thái của nó khi nó kết thúc vào mùa xuân tạo ngữ cảnh.

Nếu trạng thái không thay đổi, bạn không có gì để làm.

Nếu trạng thái của singleton có thể thay đổi, bạn sẽ phải đồng bộ hóa chính xác quyền truy cập vào trạng thái có thể thay đổi này.

+0

bean có các trường khởi tạo cuối cùng và getters cho chúng, không có nghĩa là bean này không thể có bất kỳ vấn đề nào về an toàn luồng? và câu hỏi duy nhất là liệu các lớp trường là thread an toàn hay không –

+0

Chính xác. Đậu chính nó là OK. Các trường của nó, nếu có thể thay đổi, phải được tạo thành an toàn chỉ. –

0

Lớp học của bạn sẽ không an toàn theo luồng, nếu bạn đánh dấu nó là singleton trong ngữ cảnh kể từ khi bạn khởi tạo các trường có "new" thủ công một lần khi bean được tạo và bạn sẽ có một trường hợp bộ nhớ như singleton của bạn và cho phù hợp, chủ đề của bạn chia sẻ các thể hiện của CustomGxSessionIdCacheImpl, PcrfRecord và như vậy.

Nếu bạn có thể làm cho những trường hợp mất dưới sự kiểm soát của bối cảnh mùa xuân, như:

<bean id="customGxSessionIdCache" class="package.CustomGxSessionIdCacheImpl" scope="prototype"> 

và autowire chúng trong PcrfSimulator như:

@Autowired 
private final CustomGxSessionIdCacheImpl gxSessionIdCache 

sau đó, càng sớm càng truy xuất mã lệnh của bạn trên gxSessionIdCache, spring tạo ra một cá thể mới cho mỗi truy cập và cho mỗi luồng tương ứng. Bất kỳ phương pháp nào khác trong Singleton phải được đánh dấu bằng synchronized vì chúng được mở cho acceess đa luồng. Những người độc thân mùa xuân là những người độc thân thường xuyên.

Tôi nghĩ, nói sai, nếu bạn không có trạng thái nào, thì mọi thứ đều an toàn chỉ. Nếu bạn nghĩ rằng mức độ thấp, các phương pháp cũng đã nói, tức là các biến cục bộ và nếu có nhiều luồng truy cập vào các biến này, bạn cũng có thể bị đau đầu.

+0

Cảm ơn, nhưng điều này không có nghĩa là tôi sẽ có nhiều phiên bản cache? Tôi chỉ muốn một bộ nhớ cache, được truy cập và cập nhật bởi tất cả các chủ đề. – Rory

+0

bạn cũng phải đánh dấu các phương thức của bộ nhớ cache là đã đồng bộ hóa. rõ ràng. –

+0

Tôi không hiểu tại sao phạm vi là nguyên mẫu trong ví dụ trên, tại sao không chỉ giữ nó singleton? – Rory

0

Như đã được thiết lập, lớp học của bạn không an toàn chỉ. Prototype-scope là một trong những cách để đi, nhưng nếu một bean mẫu thử nghiệm được autowired vào một bean đơn, nó vẫn sẽ có nghĩa là chỉ có một thể hiện của bean nguyên mẫu được tạo ra, có hiệu quả làm cho nó singleton là tốt.

Đồng bộ là một cách khác để đi, nhưng đó thực sự chỉ áp dụng nếu các biến dụ là nghĩa để được chia sẻ giữa các chủ đề. Tuy nhiên, nếu ý định là các biến mẫu phải là duy nhất cho mỗi chuỗi, bạn nên xem ThreadLocal thay thế.

+0

@ErhanBagdemir Bạn không chính xác. Prototype có nghĩa là một thể hiện mới được tạo ra mỗi khi bean được tiêm * vào một bean khác hoặc được yêu cầu một cách rõ ràng bằng cách sử dụng getBean(). Xem tài liệu http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-scopes-prototype (đặc biệt là 4.5.3) – pap