2012-08-06 35 views
8

Đoạn mã sau có gây ra vấn đề tương tự hay không, nếu biến 'commonSet' của phương thức này thay vào đó là trường cấp lớp. Nếu nó là một trường cấp lớp, tôi sẽ phải bọc thêm để thiết lập hoạt động trong một khối được đồng bộ hóa vì HashSet không phải là luồng an toàn. Tôi có nên làm tương tự trong mã sau đây, vì nhiều luồng được thêm vào tập hợp hoặc thậm chí chuỗi hiện tại có thể tiếp tục thay đổi tập hợp.Chủ đề Biến an toàn cục bộ cuối cùng được chuyển cho chủ đề?

public void threadCreatorFunction(final String[] args) { 
    final Set<String> commonSet = new HashSet<String>(); 

    final Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       commonSet.add(newValue()); 
      } 
     } 
    }; 

    new Thread(runnable, "T_A").start(); 
    new Thread(runnable, "T_B").start(); 
} 

Tham chiếu đến 'commonSet' bị 'khóa' bằng cách sử dụng final. Nhưng nhiều luồng hoạt động trên nó vẫn có thể làm hỏng các giá trị trong tập hợp (nó có thể chứa các bản sao?). Thứ hai, sự nhầm lẫn là do 'commonSet' là một biến mức phương thức - cùng một tham chiếu sẽ nằm trên bộ nhớ ngăn xếp của phương thức gọi (threadCreatorFunction) và bộ nhớ ngăn xếp của các phương thức chạy - điều này có đúng không?

Có khá một vài câu hỏi liên quan đến điều này:

Nhưng, tôi không thể nhìn thấy họ nhấn mạnh vào chủ đề phần an toàn như chia sẻ/chuyền của mutables.

+0

Xem thêm http://stackoverflow.com/questions/1299837/cannot-refer-to-a-non-final-variable-inside-an-inner-class-defined-in-a-differen – nos

Trả lời

9

Không, điều này hoàn toàn không an toàn cho luồng. Chỉ vì bạn đã có nó trong biến cuối cùng, điều đó có nghĩa là cả hai chủ đề sẽ thấy cùng một tham chiếu , điều đó là tốt - nhưng nó không làm cho đối tượng an toàn hơn.

Hoặc bạn cần phải đồng bộ hóa quyền truy cập hoặc sử dụng ConcurrentSkipListSet.

5

Một ví dụ thú vị.

Tham chiếu commonSet là chủ đề an toàn và không thay đổi. Nó nằm trên ngăn xếp cho chuỗi đầu tiên và một trường của lớp vô danh Runnable của bạn. (Bạn có thể thấy điều này trong trình gỡ lỗi)

Tập hợp commonSet đề cập đến có thể thay đổi và không an toàn. Bạn cần sử dụng đồng bộ hóa hoặc Khóa để làm cho chuỗi đó an toàn. (Hoặc sử dụng một bộ sưu tập chủ đề an toàn thay vì)

1

Tôi nghĩ rằng bạn đang bỏ lỡ một từ trong câu đầu tiên của bạn:

Will vấn đề mã nguyên nhân sau cùng nếu biến 'commonSet' của phương pháp này là một ??? thay vào đó là một trường cấp lớp.

Tôi nghĩ bạn có chút bối rối. Các vấn đề đồng thời không liên quan đến việc liệu tham chiếu đến cấu trúc dữ liệu có thể thay đổi của bạn được khai báo là final hay không. Bạn cần phải khai báo tham chiếu là final vì bạn đang closing over nó bên trong khai báo lớp bên trong ẩn danh cho số Runnable của bạn. Nếu bạn thực sự sẽ có nhiều chủ đề đọc/ghi cấu trúc dữ liệu thì bạn cần phải sử dụng khóa (đồng bộ hóa) hoặc sử dụng cấu trúc dữ liệu đồng thời như java.util.concurrent.ConcurrentHashMap.

+0

dòng đầu tiên đã sửa – haps10

+0

Ah, tôi đã sai — bạn có thêm một từ! – DaoWen

0

Khi người khác đã nhận xét, bạn đang nhầm lẫn một số khái niệm, chẳng hạn như cuối cùng và đồng bộ hóa.

Tôi nghĩ rằng nếu bạn giải thích những gì bạn muốn thực hiện với mã của bạn, nó sẽ dễ dàng hơn nhiều để giúp bạn. Tôi đã có ấn tượng rằng đoạn mã này là một ví dụ về mã thực tế.

Một số câu hỏi: Tại sao bộ được xác định bên trong hàm? nó có nên được chia sẻ giữa các luồng không? Cái gì mà tôi bối rối là bạn thùng hai đề với cùng một ví dụ của Runnable

new Thread(runnable, "T_A").start(); 
    new Thread(runnable, "T_B").start(); 
0

Dù commonset được sử dụng bởi chủ đề duy nhất hoặc nhiều nó chỉ là tài liệu tham khảo đó là bất di bất dịch cho các đối tượng chính thức (ví dụ, một khi giao bạn không thể gán một tham chiếu obj khác một lần nữa) tuy nhiên bạn vẫn có thể sửa đổi các nội dung được tham chiếu bởi đối tượng này bằng cách sử dụng tham chiếu đó.

Nếu nó không được chính thức một thread có thể khởi tạo nó một lần nữa và thay đổi tài liệu tham khảo commonSet = new HashSet<String>(); commonSet.add(newValue()); trong trường hợp hai chủ đề này có thể sử dụng hai commonsets khác nhau mà có lẽ không phải những gì bạn muốn

1

Các commonSet được chia sẻ giữa hai Chủ đề. Bạn đã tuyên bố nó là cuối cùng và do đó bạn đã thực hiện tham chiếu không thay đổi (bạn không thể gán lại), nhưng dữ liệu thực tế bên trong Bộ vẫn còn có thể thay đổi. Giả sử một Thread đặt một số dữ liệu vào và một số Thread khác đọc một số dữ liệu. Bất cứ khi nào thread đầu tiên đặt dữ liệu vào, bạn có thể muốn khóa Set đó để không Thread khác có thể đọc cho đến khi dữ liệu đó được ghi. Điều đó có xảy ra với HashSet không? Không hẳn.

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