2011-09-16 30 views
6

Tôi phải viết một bài kiểm tra đơn vị để kích thích một tình trạng đua để tôi có thể kiểm tra nếu tôi có thể khắc phục sự cố sau này. Vấn đề là điều kiện chủng tộc chỉ xảy ra rất hiếm khi, có thể vì máy tính của tôi chỉ có hai lõi.Cho biết tình trạng chạy đua trong Java

Mã này là một cái gì đó như sau:

class MyDateTime { 
    String getColonTime() { 
    // datetime is some kind of lazy caching variable declared somewhere(does not matter) 
    if (datetime == null) { 
     initDateTime(); //Uses lazy to initlialize variable, takes some time 
    } 
    // Colon time stores hh:mm as string 
    if (datetime.colonTime == null) { 
     StringBuilder sb = new StringBuilder(); 
     //Now do some steps to build the hh:mm string 
     //... 
     //set colon time 
     datetime.colonTime = sb.toString(); 
    } 
    return datetime.colonTime; 
    } 
} 

Giải thích: initDateTime gán một trường hợp mới để datetime, do, datetime.colonTime là null sau đó (như chúng ta muốn khởi tạo nó lười biếng, như tôi đã nói trước). Bây giờ nếu Thread A đi vào phương thức và sau đó Scheduler dừng nó ngay trước khi nó có thể chạy initDateTime(). Chủ đề B bây giờ runst getColonTime(), thấy rằng datetime vẫn là null và khởi tạo nó. datetime.colonTime là null vì vậy nếu khối thứ hai được thực hiện và datetime.colonTime nhận giá trị của StringBuilder. Nếu sau đó trình lên lịch dừng luồng giữa dòng này và câu lệnh return và tiếp tục lại luồng A, điều sau sẽ xảy ra: Khi A bị dừng ngay trước khi initDateTime được gọi, A bây giờ gọi initDateTime(), sẽ loại đặt lại đối tượng datetime, thiết lập datetime.colonTime thành null một lần nữa. Thread A sau đó sẽ nhập thứ hai nếu block, nhưng scheduler sẽ làm gián đoạn A trước datetime.colonTime = sb.toString(); được gọi là. Như một kết luận, dateTime.colonTime vẫn là null. Bây giờ trình lên lịch sẽ tiếp tục B và phương thức trả về null.

Tôi cố gắng để chọc giận các điều kiện chủng tộc bằng việc có một số đề gọi getColonTime() cho một đơn (chính thức) thể hiện của MyDateTime, nhưng nó chỉ thất bại trong một số trường hợp hiếm extreeemly :( Bất kỳ gợi ý làm thế nào để viết một JUnit "test"?

+3

Trước tiên, bạn có thể thử sử dụng trình gỡ lỗi để kích động tình trạng chủng tộc. I E. bắt đầu một thread, bắt nó trên một số breakpoint (như giữa if's) và bắt đầu một cái khác - và cứ thế. Sau khi bạn nhận được ý tưởng như thế nào RC xảy ra (có vẻ như bạn không có điều đó bây giờ) bạn có thể viết một bài kiểm tra đơn vị thành công – pupssman

+0

Tôi không thấy làm thế nào bạn có thể nhận được 'trả về datetime.colonTime; 'và lấy lại null. Bạn có chắc chắn nó không phải là một vấn đề với cách bạn đang xây dựng chuỗi hh: mm? Có thể thêm mã đó vào câu hỏi của bạn để chúng tôi có thể xem xét điều đó. – Windle

+0

Tôi đã thêm một số giải thích bổ sung tại sao nó có thể xảy ra. Phải thừa nhận nó không phải là rất rõ ràng – user3001

Trả lời

4

Bạn có thể xem Thread Weaver hoặc có thể có các khung công tác khác để thử nghiệm mã đa luồng. Tôi đã không sử dụng nó, nhưng Users' Guide trông như thể nó được thiết kế cho chính xác loại thử nghiệm này.

+0

Tôi đã thấy nó, nhưng tôi không biết nó phù hợp như thế nào. Kinh nghiệm với điều đó, bất cứ ai? – user3001

+0

Tôi đã thử chỉ dệt. Nó hoạt động tuyệt vời để thử nghiệm nếu bạn biết vấn đề ở đâu. Tuy nhiên, bạn không thể thực hiện các phép thử N x N trên các dòng của một phương thức (tôi đã hỏi trong nhóm thảo luận). – user3001

7

Như bạn đã đề cập, các điều kiện chủng tộc là cực kỳ khó khăn để tái tạo một cách nhất quán.Tuy nhiên, pháp luật trung bình là ở bên bạn. Nếu bạn tạo một thử nghiệm mà bạn mong đợi có thể thất bại một trăm lần, và sau đó làm cho nó xảy ra hàng nghìn lần, có thể bạn sẽ gặp lỗi khá nhất quán trong mã cũ của mình.Vì vậy, trong việc tuân thủ các nguyên tắc TDD, bạn nên bắt đầu với mã như trước đây, đưa ra một thử nghiệm lặp lại đủ lần không nhất quán với mã cũ, sau đó thay đổi mã mới của bạn và đảm bảo mã không thành công.

+0

Bạn có thể có một xác suất tốt của các thử nghiệm thất bại, nhưng xác suất cao hơn bạn yêu cầu các thử nghiệm sẽ mất nhiều thời gian để chạy. Các bài kiểm tra đơn vị được cho là nhanh. (Nhưng tôi không có một ý tưởng tốt hơn.) –

0

Tôi biết bài đăng này khá cũ nhưng tôi phải đối mặt với một tình huống tương tự. Những gì tôi có xu hướng làm là ủng hộ điều kiện chủng tộc với giấc ngủ.

Trong trường hợp của bạn, tôi sẽ làm một cái gì đó giống như

class MyDateTime { 
     String getColonTime() throws InterruptedException{ 
      if (datetime == null) { 
       Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that multiple threads enter here and reset colonTime. 
       initDateTime(); 
      } 
      Thread.sleep(new Random().nextInt(100); //Wait to enhance the chances that colonTime stays null for a while. 
      if (datetime.colonTime == null) { 
       StringBuilder sb = new StringBuilder(); 
       datetime.colonTime = sb.toString(); 
      } 
      Thread.sleep(new Random().nextInt(100); //Wait to favour reset of colonTime by another thread in the meantime. 
      return datetime.colonTime; 
     } 
    } 

Nhưng rõ ràng điều này trở nên lộn xộn khá nhanh chóng. Tôi muốn có một số cách để buộc các Scheduler để khám phá tất cả các đường dẫn cho một số "điểm break".

Khi bài đăng có một chút cũ, tôi đã tự hỏi liệu bạn có tìm thấy những cách tốt để kiểm tra các điều kiện chủng tộc trong Java hay không. Bất kỳ lời khuyên nào để chia sẻ?

Cảm ơn bạn

+1

Như tôi đã nói trong câu trả lời được chấp nhận, Thợ dệt chỉ là một công cụ tuyệt vời và tôi đoán bây giờ có những công cụ khác. Ví dụ IntelliJ nhận được một số hỗ trợ gỡ lỗi đa luồng nếu tôi nhớ nó một cách chính xác. Ngoài ra thống kê là về phía bạn: Nếu bạn lặp lại một bài kiểm tra thường xuyên đủ, bạn chắc chắn sẽ đạt được điều kiện chủng tộc một lần trong một thời gian :) Xem thêm https://github.com/junit-team/junit4/wiki/Multithreaded-code - và đồng thời – user3001

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