Tỡnh trạng “đua tranh”

Một phần của tài liệu Bài giảng ngôn ngữ lập trình Java doc (Trang 141 - 142)

V. Đồng bộ thread

V.1Tỡnh trạng “đua tranh”

Trong phần tiếp theo, chỳng ta mụ phỏng một ngõn hàng cú rất nhiều tài khoản khỏch hàng. Chỳng ta thử thiết kế một chương trỡnh để chuyển tiền ngẫu nhiờn giữa cỏc tài khoản. Mỗi tài khoản cú một thread riờng. Mỗi giao dịch thực hiện việc chuyển tiền từ account sang một account ngẫu nhiờn khỏc.

Ta cú một class Bank với phương thức transfer để chuyển tiền. Nếu account chuyển khụng đủ tiền, giao dịch kết thỳc ngay.

public void transfer(int from, int to, double amount) {

System.out.print(Thread.currentThread()); accounts[from] -= amount;

System.out.printf(" %10.2f from %d to %d", amount, from, to); accounts[to] += amount;

System.out.printf(" Số dư: %10.2f%n", getTotalBalance()); }

Sau đõy là đoạn code cho class transferRunnable: class TransferRunnable implements Runnable {

. . .

public void run() {

try {

int toAccount = (int) (bank.size() * Math.random()); double amount = maxAmount * Math.random(); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int) (DELAY * Math.random())); }

catch(InterruptedException e) {} }

}

Khi chương trỡnh chạy, ta khụng biết được trong mỗi tài khoản cũn bao nhiờu tiền nhưng tổng số tiền của tất cả cỏc tài khoản là khụng đổi. Chương trỡnh trờn chạy và khụng bao giờ dừng lại, ta phải ấn Ctrl + C để dừng nú.

Tuy nhiờn, trong một số tỡnh huống chương trỡnh trờn cú thể gõy lỗi và in ra tổng số tiền khỏc nhau, đú là khi cú nhiều hơn một tài khoản cựng chuyển tiền đến một tài khoản khỏc, tức là cựng thực hiện cõu lệnh:

account[to] += amount;

Giả sử đõy là một hành vi đơn vị (atomic- hành vi chỉ chiếm một chu kỳ thực hiện lệnh của CPU), khi đú mỗi thread sẽ thực hiện phộp tớnh này một cỏch tuần tự mà khụng gõy ảnh hưởng vỡ trong một thời điểm, CPU cũng chỉ phục vụ được cho một thread.

Tuy nhiờn, phộp tớnh này lại khụng phải là atomic, cụng việc cú thể phải làm là: 1- Load giỏ trị account[to] vào thanh ghi

2- Cộng với account

3- Load kết quả ngược trả lại cho account[to]

Giả sử cú 2 thread là thread_1 và thread_2 cựng thực hiện đến dũng lệnh này. Thread_1 thực hiện xong bước 1 và 2 thỡ bị ngắt, sau đú thread_2 sẽ thực hiện cõu lệnh trờn với đầy đủ 3 bước tức là account[to] đó bị thay đổi giỏ trị. Tiếp theo, thread_1 thức dậy và làm tiếp bước 3, account[to] lỳc này đó ghi đố giỏ trị do thread_2 cập nhật. Điều này dẫn tới việc tổng số tiền bị thay đổi, phần tiền do thread_2 chuyển cho account[to] đó bị mất.

Một phần của tài liệu Bài giảng ngôn ngữ lập trình Java doc (Trang 141 - 142)