Đồng bộ

Phương Thức Đồng Bộ Hóa Đa Luồng Trong Java, Đồng Bộ Hóa Nghĩa Là Gì

Các luồng chia sẻ với nhau cùng một không gian bộ nhớ, nghĩa là chúng có thể chia sè với nhau các tài nguyên. Khi có nhiều hon một luồng cùng muốn sir dụng một tài nguyên sẽ xuất hiện tình trạng câng thẳng, ở đó chi cho phép một luồng được quyền truy cập. Vi dụ, một luồng muốn truy cập vào một biến để đọc dữ liệu, trong khi một luồng khác lại muốn thay đổi biến dữ liệu ở cùng một thời điểm. Để cho các luồng chia sẻ với nhau được các tài nguyên và hoạt động hiệu quà, luôn đảm bão nhất quán dữ liệu thì phài có cơ chế đồng bộ chúng. Java cung cấp cơ chế đồng bộ ờ mức cao để điều khiển truy cập của các luồng vào nhũng tài nguyên dùng chung.

Đang xem: đồng bộ hóa đa luồng

1. Các hàm đồng bộ

Như chúng ta đã biết, khái niệm semaphore (monitor được Tony Hoare đề xuất) thường được sử dụng để điều khiển đồng bộ các hoạt động truy cập vào những tài nguyên dùng chung. Một luồng muốn truy cập vào một tài nguyên dùng chung (như biến dữ liệu) thì trước tiên nó phải yêu cầu để có được monitor riêng. Khi có được monitor thì luồng như có được “chìa khóa” để “mờ cửa” vào miền “tranh chấp” (tài nguyên dùng chung) để sừ dụng những tài nguyên đó.

Cơ chế monitor thực hiện hai nguyên tắc đồng bộ chính:

Không một luồng nào khác được phân monitor khi có một luồng đã yêu cầu và đang chiếm giữ nó. Những luồng khác yêu cầu monitor sẽ phải chờ cho đến khi monitor được giải phóng.Khi có một luồng giải phóng (ra khỏi) monitor, một trong số các luồng đang chờ monitor có thể truy cập vào tài nguyên dùng chung tương ứng với monitor đó.

Mọi đối tượng trong Java đều có monitor, mỗi đối tượng có thể được sử dụng như một khóa loại trừ nhau và cung cấp khả năng đồng bộ truy cập vào những tài nguyên chia sẻ.

Trong lập trinh có hai cách để thực hiện việc đồng bộ:

Các hàm (phương thức) được đồng bộCác khối được đồng bộCác hàm đồng bộ

Hàm của một lớp chi cho phép một luồng được thực hiện ờ một thời điểm thì nó phài khai báo synchronized, được gọi là hàm đồng bộ. Một luồng muốn gọi để thực hiện một hàm đồng bộ thì nó phải chò để có được monitor của đối tượng có hàm đó. Trong khi một luồng đang thực hiện hàm đồng bộ thì tất cà các luồng khác muốn thực hiện hàm này của cùng một đối tượng, đều phải chò cho đến khi luồng đó thực hiện xong và được giải phóng. Bằng cách đó, những hàm được đồng bộ sẽ không bao giờ bị tắc nghẽn. Những hàm không được đồng bộ cùa đối tượng cỏ thể được gọi thực hiện mọi lúc bời bất kỳ đối tượng nào.

Ví dụ 1.4. Chương trình sau sử dụng Thread để tính tổng các phần tử của một màng.

public class Adder{ public int<> array; private int sum = 0;

private int index = 0;

private int noOfThread = 10;

private int threadQuit;

public Adder(){ threadQuit = 0; array = new int<1000>; initializeArray() ;

startThread();

}

public synchronized int getNextlndex(){ if(index ) ()}

Khi một luồng muốn vào khối mã lệnh đồng bộ để thực hiện thì nó phải ycu cầu dề có được monitor ờ đối tương tham chiếu, nhũng luồng khác sẽ phái chờ cho đến khi monitor được giải phóng. Ví dụ,

class Client!

BankAccount account;

//…

public void updateTransaction(){

synchronized (account) { // (1) Khối đồng bộ

account. update 0 ; //(2)

}

}

}

Câu lệnh (2) được đồng bộ trong khối đồng bộ (1) theo đối tượng account của lóp BankAccount. Khi có một số luồng đồng thời muốn thực hiện updateTransaction () dối VỚI một dối tượng của lóp Client thi ờ mồi thời điểm, câu lệnh (2) chì thực hiện được ở một luồng.

2. Sự trao đổi giữa các luồng không đống bộ

Để loại bỏ được sự truy cập đồng thời cùa nhiều luồng vào những đối tượng dùng chung, chúng ta phải biết cách để đồng bộ chúng.

Ví dụ 1.5. Chúng ta hãy xây dựng hệ thống ngân hàng có 10 tài khoản, trong đó có các giao dịch chuyển tiền giữa các tài khoản với nhau môt cách ngẫu nhiên. Chương trình tạo ra 10 luồng cho 10 tài khoản. Mỗi giao dịch được một luồng phục vụ sẽ chuyển một lượng tiền ngẫu nhiên từ một tài khoản sang tài khoản khác.

Xem thêm: phần mềm làm ảnh thẻ miễn phí

Chúng ta xây dựng lóp Bank có hàm transfer () để chuyển tiền từ một tài khoản sang tài khoản khác nếu số tiền ở tài khoản gốc còn nhiều tiền hơn số tiền cần chuyển.

startThread();

}

public synchronized int getNextlndex(){ i f ( index public void transfer(ìnt from, int to, int amount){ if(accounts Nạp accounts < to > vào thanh ghiCộng số tiền trong tài khoản accounts với amountLưu lại kết quả cho accounts .

Giả sứ có hai tài khoản cùng chuyển tiền vào cùng một tài khoản. Chúng ta có thể giả thiết luồng thứ nhất thực hiện bước 1 và 2 với amount = 500, sau đó nó bị ngắt. Luồng ửiứ hai có thểtiụrc hiện trọn ven cả ba bước trên với amount = > 000, và luồng thứ nhai kết thúc việc cạp nhật bằng cách thực hiện nốt bước 3. Quá trình này được mô tả như ở hình 1.3.

*

Kết thúc luồng thứ nhất, accounts (to> có 6000, nhưng ngay sau đó luồng thứ hai kết thúc thì cũng chính tài khoản đó chưa chuyển tiền đi đâu cà, nhưng lại chỉ còn 5500. Trong trường hợp này, ờ tài khoản nhận tiền chuyển đến phải có là 6500 đơn vị tiền mới là chinh xác.

Như vậy, hoạt động giao dịch giữa các tài khoản trong ngân hàng sẽ không còn chính xác, nghĩa là xuất hiện sự sai lệch về dữ liệu, không đảm bảo tính toàn vẹn của dữ liệu. Nhưng, nếu tất cả các luồng cùng thực hiện với cùng một mức ưu tiên thi sẽ rất chậm, bởi vì mỗi luồng sau khi thực hiện “một chút” công việc lại phải đi “ngủ” để các luồng khác thực hiện, rồi lại tiếp tục, v.v.

Các vấn đề trên sẽ được giải quyết khí chúng ta sử dụng cơ chế điều khiển hoạt động của các luồng theo mức ưu tiên và đồng bộ hoá để đảm báo rằng một luồng thực hiện xong việc cập nhật rồi mới trao quyền cho luồng tiếp theo.

Như trên đã nêu, Java sừ dụng cơ chế đồng bộ khá hiệu quả là monitor. Một hàm sẽ không bị ngất nếu bạn khai báo nó là synchronized, như

public synchronized void transfer(int from, int to, int amount) { if(accounts }

public synchronized void test ( ) { int sum = 0;

for(int i = 0; i notify () đưa một luồng bẩt kỳ ra khỏi danh sách hàng đợi.no ti fyAl 1 () đưa tất cả các luồng ra khỏi danh sách hàng đợi.

Xem thêm: Tải Miễn Phí Danh Sách Email Cá Nhân Miễn Phí Để download, Hơn 1 Triệu Data Khách Hàng Miễn Phí Để download

Những luồng đưa ra khỏi danh sách hàng đợi sê được bộ lập lịch kích hoạt chúng. Ngay tức khắc, luồng nào chiếm được khóa đối tượng thi sẽ bắt đầu thực hiện. Như vậy, trong hàm transfer () chúng ta gọi notifyAll 0 khi kểt thúc việc chuyển tiền để một trong các luồng có thể được tiếp tục thực hiện và tránh bế tắc. Cuối cùng chương trình sừ dụng cơ chế đồng bộ được viết lại như sau.

Show More

Related Articles

Back to top button
Close