Thread interference trong Java

Chào mừng các bạn đã trở lại với thachleblog. Ở bài trước mình đã giới thiệụ về multi thread và sự khác nhau giữa sử dụng runable interface và thread class trong Java. Nhưng việc sử dụng multi thread cũng gặp các vấn đề, một trong những vấn đề đó là thread interference hay còn được gọi là race condition. Vậy thread interference là gì? Tác động của nó như thế nào? Chúng ta cùng bắt đầu nhé.

Chúng ta cùng xem ví dụ:

– Class Account có method increament(), method này sẽ thực hiện cộng 1 số nguyên truyền vào cho giá trị amount

  1. package thach.le.threadinterference;
  2. public class Account {
  3. private int amount = 0;
  4. public void increment(int num) {
  5. amount = amount + num;
  6. }
  7. public int value() {
  8. return amount;
  9. }
  10. }
  • Trường hợp 1: ta gọi 1000 lần method increament() mà không sử dụng multi thread:
  1. package thach.le.threadinterference;
  2. public class NonMultiThread {
  3. public static void main(String[] args) {
  4. Account account = new Account();
  5. for (int i = 0; i < 1000; i++){
  6. account.increment(1);
  7. }
  8. System.out.println("Amount: " + account.value());
  9. }
  10. }

Kết quả sẽ luôn là 1000
thread interference trong java
– Trường hợp 2: sử dụng 1000 thread cùng gọi đồng thời method increment(), sử dụng multi thread:

  1. package thach.le.threadinterference;
  2. public class ThreadInterference {
  3. public static void main(String[] args) throws InterruptedException {
  4. Account account= new Account();
  5. Runnable runnable = () -> {
  6. account.increment(1);
  7. };
  8. // use a lot of theads will be easy to see the issue
  9. Thread [] threads = new Thread[1000];
  10. for (int i = 0; i < threads.length; i++) {
  11. threads[i] = new Thread(runnable);
  12. threads[i].start();
  13. }
  14. // wait for all thread are finished
  15. for (int i = 0; i < threads.length; i++) {
  16. threads[i].join();
  17. }
  18. System.out.println("Count: " + account.value());
  19. }
  20. }

Kết quả sẽ là khác nhau ở các lần chạy, có thể là 1000, 999, 998, 997 … Lý do mình sử dụng đến 1000 thread là vì khi sử dụng 2, hoặc số ít thread, khả năng xảy ra vấn đề này rất thấp, mình sử dụng số lượng lớn để chúng ta có thể dễ thấy.

Ví dụ vừa rồi chính là thread interference, thread interference chính là vấn đề không đồng nhất khi xảy ra tranh chấp của dữ liệu dùng chung (share data) giữa các thread. Ở ví dụ trên, khi một thread chiếm giữ biến amount và thực hiện phép toán tăng thêm 1 đơn vị. Nhưng rất có thể ngay tại thời điểm đó, 1 hoặc nhiều thread khác cũng đang thực hiện phép toán tăng thêm một đơn vị với giá trị chưa được cập nhật là 0. Do đó, dẫn đến kết quả sai lệch.

Java cũng đã cung cấp các giải pháp để giải quyết vấn đề này, một trong số đó chính là sử dụng sychronization. Vậy sử dụng synchronization như thế nào? Và sử dụng synchronization có phát sinh vấn đề gì không? chúng ta sẽ cùng tìm hiểu qua bài viết tiếp theo của mình nhé.

Rất mong nhận được ý kiến đóng góp của tất cả các bạn. Xin cảm ơn!

Tham khảo thêm:
https://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html