2009-07-15 34 views
20

Có bất kỳ vấn đề đồng thời nào với một chuỗi đọc từ một chỉ mục của một mảng hay không, trong khi một luồng khác ghi vào một chỉ mục khác của mảng, miễn là các chỉ mục khác nhau?java array thread-safety

ví dụ: (Ví dụ này không nhất thiết phải đề nghị cho sử dụng thực tế, chỉ để minh họa cho quan điểm của tôi)

class Test1 
{ 
    static final private int N = 4096; 
    final private int[] x = new int[N]; 
    final private AtomicInteger nwritten = new AtomicInteger(0); 
    // invariant: 
    // all values x[i] where 0 <= i < nwritten.get() are immutable 

    // read() is not synchronized since we want it to be fast 
    int read(int index) { 
     if (index >= nwritten.get()) 
      throw new IllegalArgumentException(); 
     return x[index]; 
    } 
    // write() is synchronized to handle multiple writers 
    // (using compare-and-set techniques to avoid blocking algorithms 
    // is nontrivial) 
    synchronized void write(int x_i) { 
     int index = nwriting.get(); 
     if (index >= N) 
      throw SomeExceptionThatIndicatesArrayIsFull(); 
     x[index] = x_i; 
     // from this point forward, x[index] is fixed in stone 
     nwriting.set(index+1); 
    }  
} 

chỉnh sửa: phê bình ví dụ này không phải là câu hỏi của tôi, tôi theo nghĩa đen chỉ muốn biết nếu truy cập mảng tới một chỉ số, đồng thời để truy cập của một chỉ mục khác, đặt ra các vấn đề đồng thời, không thể nghĩ ra một ví dụ đơn giản.

Trả lời

12

Trong khi bạn sẽ không nhận được một trạng thái không hợp lệ bằng cách thay đổi các mảng như bạn đề cập, bạn sẽ có cùng một vấn đề xảy ra khi hai luồng đang xem một số nguyên không bay hơi mà không cần đồng bộ hóa (xem phần trong Hướng dẫn Java trên Memory Consistency Errors). Về cơ bản, vấn đề là Thread 1 có thể viết một giá trị trong không gian i, nhưng không có sự đảm bảo khi (hoặc nếu) Thread 2 sẽ thấy sự thay đổi.

Lớp học java.util.concurrent.atomic.AtomicIntegerArray làm những gì bạn muốn làm.

+0

cảm ơn ... drat, tôi muốn sử dụng mảng byte [] và có vẻ như không có động vật nguyên tử nào như vậy .... Tôi đoán tôi sẽ chỉ sử dụng các phương pháp đồng bộ và giữ nó đơn giản. –

+2

Nếu bạn có nhiều lần đọc hơn viết, bạn có thể muốn xem java.util.concurrent.locks.ReadWriteLock –

+0

huh, thú vị ... –

4

Ví dụ này có rất nhiều nội dung khác với câu hỏi văn xuôi.

Câu trả lời cho câu hỏi đó là các phần tử riêng biệt của một mảng được truy cập độc lập, vì vậy bạn không cần đồng bộ hóa nếu hai luồng thay đổi các phần tử khác nhau.

Tuy nhiên, mô hình bộ nhớ Java không đảm bảo (mà tôi biết) rằng giá trị được viết bởi một chuỗi sẽ hiển thị với một chuỗi khác, trừ khi bạn đồng bộ hóa quyền truy cập.

Tùy thuộc vào những gì bạn đang thực sự cố gắng hoàn thành, có khả năng là java.util.concurrent đã có một lớp học sẽ làm điều đó cho bạn. Và nếu không, tôi vẫn khuyên bạn nên xem mã nguồn cho ConcurrentHashMap, vì mã của bạn dường như đang làm điều tương tự để quản lý bảng băm.

1

Tôi không thực sự chắc chắn nếu chỉ đồng bộ hóa phương thức write, trong khi rời khỏi phương thức read không được đồng bộ hóa sẽ hoạt động. Không thực sự là tất cả những hậu quả, nhưng ít nhất nó có thể dẫn đến phương pháp read trả lại một số giá trị vừa được overriden bởi write.

1

Có, vì khả năng xen kẽ bộ nhớ cache xấu vẫn có thể xảy ra trong môi trường nhiều CPU/lõi. Có rất nhiều tùy chọn để tránh nó:

  • Sử dụng thư viện không an toàn Sun-tin tới nguyên tử thiết lập một phần tử trong một mảng (hoặc thêm tính năng jsr166y trong Java7
  • Sử dụng AtomicXYZ [] array
  • Sử dụng tùy chỉnh phản đối với một lĩnh vực không ổn định và có một loạt các đối tượng đó.
  • Sử dụng ParallelArray của jsr166y phụ lục thay vì trong thuật toán của bạn
1

Từ read() là không đồng bộ bạn có thể có scen sau Ario:

Thread A enters write() method 
Thread A writes to nwriting = 0; 
Thread B reads from nwriting =0; 
Thread A increments nwriting. nwriting=1 
Thread A exits write(); 

Vì bạn muốn đảm bảo rằng địa chỉ biến của bạn không bao giờ xung đột, những gì về một cái gì đó tương tự (chiết khấu vấn đề chỉ số mảng):

int i; 
synchronized int curr(){ return i; } 
synchronized int next(){ return ++i;} 

int read() { 
     return values[curr()]; 
    } 

void write(int x){ 
    values[next()]=x; 
} 
+0

cảm ơn, nhưng không phải câu hỏi của tôi và kịch bản của bạn không thể xảy ra (bước 2 và 3 sẽ không bao giờ xảy ra) –