Đồng bộ hóa đa luồng trong Java
Bài đăng này đã không được cập nhật trong 3 năm
Các ứng dụng chạy đa luồng đem lại rất nhiều lời ích, giúp tận dụng được các CPU đa nhân để phân công cho cho mỗi nhận vật lý 1 luồng xử lý để tăng tốc độ tính toán của bài toán. Hay hiện tại trong 1 số ứng dụng sử dụng GPU để tính toán hiệu năng cao dựa vào số nhân vô cùng lớn của GPU.
Nhưng trong 1 số trường hợp nếu các luồng xử lý có sử dụng chung 1 biến, mảng dữ liệu thì có thể sẽ sảy xung đột giữa các luồng xử lý. VD: Khi đi rút tiền ở cây ATM chúng ta ấn nút rút là máy sẽ tự động nhả tiền cho chúng ta, nhưng giả sử bạn có 2 thẻ ATM, tại cùng lúc bạn đứng ở Thái Nguyên để rút tiền, còn người khác cầm thẻ kia đứng ở Bắc Ninh rút tiền. Nếu trong tài khoản của bạn có 1tr, bạn thực hiện rút 500, bạn kia thực hiện rút 700. Chuyện gì sẽ xảy ra nếu hai bạn cùng ấn nút “Rút” tại cùng một thời điểm. Chắc chắn ngân hàng sẽ không bỏ ra đưa bạn 1200k đâu. Mà thay vì thế một trong hai bạn sẽ không rút được!.
Trong Java nếu bạn sử dụng đa luồng mà có nhiều hơn 1 luồng cùng thao tác vào 1 dữ liệu chung thì Java sẽ trả về 1 Exception. Khi ấy chúng ta cần 1 cơ chế để khóa hay đồng bộ dữ liệu sử dụng chung để tại 1 thời điểm chỉ có 1 luồng được phép truy cập. Java cung cấp từ khóa synchronized dùng để đồng bộ hóa khi có tranh chấp xảy ra.
Các bạn thử chạy qua chương trình này để thấy dc rõ hơn.
Rõ ràng là mục đích của bài toán là vừa tăng j,i và vừa in ra giá trị. Với mong muốn là chúng ta có 2 giá trị i,j bằng nhau. Nhưng ở chỗ khoanh đỏ đã có xảy ra xung đột, khi 1 Thread đang thực hiện chức năng tăng i,j trong hàm in() thì có 1 Thread khác cũng truy cập biến count và thực hiện in ra màn hình giá trị 2 biến đó. Và kết quả là ta có giá trị 2 biến i và j là ko bằng nhau.
Ở đây cơ chế đồng bộ sẽ giúp bạn xử lý vấn đề này.
Có 2 cơ chế đồng bộ được sử dụng trong Java là đồng bộ phương thức hoặc đồng bộ Object.
1. Đồng bộ Object:
Chúng ta sẽ thêm từ khóa synchronized(object) trước khi chung ta thực hiện gọi hàm.
Ở cách đồng bộ này thì hàm synchronized sẽ khóa biến dữ liệu count và chỉ cho phép tại 1 thời điểm chỉ có 1 luồng được phép truy cập và sử dụng biến này và khi thực hiện xong hàm in() hoặc out() thì biến sẽ dc giải phóng để các luồng (hay hàm) khác có thể truy cập.
2. Đồng bộ phương thức: Chúng ta sẽ thêm từ khóa synchronized trước phương thức ta muốn đồng bộ.
Như này ở đây, 2 hàm in() và out() cùng truy cập tới 2 biến i và j. Nên khi ta sử dụng thêm từ khóa synchronized ở đầu phương thức thì khi hàm in() được gọi nó sẽ sử dụng 2 biến i và j và khóa 2 biến này lại, khi nào hàm thực hiện xong thì sẽ giải phóng 2 biến i va j để các hàm khác có thể truy cập được.
Chú ý: 2 cách đồng bộ này đều cho kết quả giống nhau, nhưng cách thực hiện có đôi chút khác nhau và sử dụng tùy biến theo từng trường hợp.
- Cách 1 hay được sử dụng khi ta có 1 Object chung và gọi các phương thức bên ngoài để cùng xử lý, tính toán trên Object dữ liệu chung đấy.
- Cách 2 hay được sử dụng khi trong 1 Class có nhiều hàm cùng sử dụng 1 Object để xử lý và Class này được gọi thực thi ở 1 phương thức khác.
All rights reserved