Ví dụ về một trạng thái đua tranh

Một phần của tài liệu Bài Giảng Lập Trình Java - Đại Học Thủy Lợi.pdf (Trang 387 - 392)

Chương 9. LẬP TRÌNH ĐỒNG THỜI

9.5.1. Ví dụ về một trạng thái đua tranh

Đe tránh dữ liệu chia sẻ bởi nhiều luồng bị hỏng, bạn phải học cách để đồng bộ quyền truy cập. Trong phần này, bạn sẽ tìm hiểu điều gì sẽ xảy ra nếu bạn không sử dụng sự đồng bộ. Trongphầntiếp theo, bạn sẽ tìm hiếu cách đếđồngbộ quyền truy cập dữ liệu.

Trong chương trình ví dụ tiếp theo, chúng ta mô phỏng một ngân hàng với một số lượng tài khoản. Chúng ta tạo ngẫu nhiên các giao dịchđể chuyển tiền giữa các tài khoản này. Mỗitài khoản có một luồng. Mỗi giao dịch sẽ chuyển một lượng tiềnngẫu nhiêntừtài khoản đượcquản lý luồng đang xét tới một tài khoản ngẫu nhiên khác.

Đoạn mã mô phỏng rất trực quan. Chúng ta có một lớp Bank với phương thức transfer. Phương thức này chuyển một lượng tiền từ một tài khoản sang tài khoản khác (Chúng ta không cần lo lắng về trạng thái âm của tài khoản). Dưới đây là đoạn mã cho phương thức transfer củalópBank.

public void transfer(int from, int to, doubleamount)

// CHÚ Ý: Phương thức này khôngantoàn khi được gọibởi nhiều luồng {

System.out.print(Thread.currentThread());

accounts [from] -= amount;

System.out.printf(" %10.2ffrom %d to%d", amount, from, to);

accounts [to] += amount;

System.out.printf(" Total Balance: %10.2f%n", getTotalBalanceO);

}__________________________________________________________________

Đây là đoạn mã cho những thể hiện Runnable. Phương thức run thực hiện chuyển tiền liên tục ra khỏi một tài khoản ngân hàng đang được xét. Trong mỗi lần lặp, phương thức run lấy mộttài khoản đích ngẫu nhiên và một lượng tiền ngẫu nhiên, rồi gọi phương thứctransfer trên đối tượngngân hàngvà sau đó “ngủ”.

Runnable r = 0 -> { try{

while (true) {

int toAccount = (int) (bank.size() * Math.randomO);

doubleamount= MAX_AMOUNT * Math.random();

bank.transfer(fromAccount, toAccount, amount);

Thread.sleep((int) (DELAY* Math.random()));

} }

catch (InterruptedException e) { }

};__________________________________________________________________

Khi mô phỏng này chạy, chúng takhông biết lượng tiền có trong một tài khoản ngân hàng bất kỳ tại một thời điểmbất kỳ. Nhưng chúngta đều biếtrằng, tổng lượng tiền trong

tất cả tài khoản nên giữ không đổi bởi vì tất cả việc chúng ta làm là di chuyển tiền từ tài khoản này sang tài khoản khác.

Khi kết thúc mỗi giao dịch, phương thức transfer tính toán lại tổng số và in nó ra màn hình.

Chương trình sẽ không bao giờ dừng, do đó bạn phải ấn CRTL+C nếu muốn thoát chươngtrình.

Đây là một đoạn in ra tiêubiếu của chương trình:

Thread[Th read-11,5,main]

Th read [Th read-12,5,main]

Thread[Th read-14,5,mai n]

Thread[Th read-13,5,mai n]

Thread[Thread-36,5,main]

Thread[Thread-35,5,main]

Th read [Th read-37,5,main]

Th read [Th read-34,5,main]

Th read [Th read-36,5,mai n]

588.48 from 11 to 44 Total Balance: 100000.00 976.11 from 12 to 22 Total Balance: 100000.00 521.51 from 14to 22 Total Balance: 100000.00 359.89 from 13to 81 Total Balance: 100000.00 401.71 from 36to 73 Total Balance: 99291.06 691.46 from 35to 77 Total Balance: 99291.06 78.64 from 37 to 3 Total Balance: 99291.06 197.11 from 34 to 69 Total Balance: 99291.06

85.96 from 36 to 4 Total Balance: 99291.06 Thread[Th read-4,5,mai n]Thread[Thread-33,5,mai n]

99979.24

627.50 from 4 to 5 Total Balance: 99979.24

7.31 from 31 to 32 Total Balance:

Như bạn có thể thấy, một điều gì đó không đúng đã xảy ra. Với một vài giao dịch, tổng số tiền trong ngân hàng giữ ở mức $100000, đây là giá trị tổng đúng cho 100 tài khoản, mỗi tài khoản ban đầu có $1000. Nhưng sau một khoảng thời gian, tổng lượng tiền này thay đổi một chút, không còn là $100000 nữa. Khi bạn chạy chương trình này, những lỗi có thể xảy ra nhanh chóng hoặc chúng ta phải chờmột khoảng thời gian dài để giá trị tổng trờ nên sai lệch. Tình huống này không tạo cho chúng ta sự tin cậy và bạn có thể không muốn gửi tiền bạn kiếm được vào một ngânhàng như the!

Chương trình 9.6 và 9.7 hoàn thiện của ví dụ này được chỉ ra sau đây. Bạn hãy thử chỉ ra vấn đề trong chươngtrình này. Chúngtôi sẽ giải mã bímật ở phầntiếptheo.

Chương trình 9.6

// Chương trình minh họa việc dữ liệu bị hỏng khi nhiều luồng truy cập vào cùng một cấu trúcdữ liệu.

public class UnsynchBankTest {

public static final int NACCOƯNTS = 100;

public static finaldouble INITIAL-BALANCE = 1000;

public static final double MAX-AMOUNT = 1000;

public static final int DELAY = 10;

public static void main(String[] args) {

Bank bank= newBank(NACCOUNTS, INITIAL-BALANCE);

for (int i = 0; i < NACCOUNTS; i++) { int fromAccount= i;

Runnable r = 0 -> { try {

while (true) {

int toAccount = (int) (bank.sizef) * Math.randomO);

double amount = MAX-AMOUNT * Math.randomf);

bank.transfer(fromAccount, toAccount,amount);

Thread.sleep((int) (DELAY* Math.randomQ));

} }

catch (InterruptedException e) { }

};

Threadt = new Thread(r);

t.start();

} } }

Chương trình 9.7 import java.util.*;

11Lớp định nghĩamộtngân hàng vớimộtsố tài khoản ngânhàng public class Bank {

private final double [] accounts;

ỵ**

* Khởitạo lớp ngân hàng

* @param n: số tài khoản

* @param initialBalance: số dư ban đầu cho mỗi tài khoản

7

public Bank(int n, doubleinitialBalance) { accounts = new double[n];

Arrays, fill (accounts, initialBalance);

}

ỵ**

* Chuyểntiền từ tài khoản này sangtài khoản khác

* @param from: tài khoản nguồn

* @param to: tài khoản đích

* @param amount: lượngtiền cầnchuyển

7

publicvoid transfer(int from, int to, double amount) { if (accounts [from] < amount) return;

System.out.print(Thread.currentThread());

accounts[from] -=amount;

System.out.printff" %10.2ffrom %dto %d", amount, from, to);

accounts [to] += amount;

System.out.printff' Total Balance: %10.2f%n", getTotalBalancef));

}

ỵ**

* Lấy về tổng số dư củatất cả tàikhoản

* @return: trả về tổng sốdư

7

public double getTotalBalance() {

double sum= 0;

for (double a: accounts) sum += a;

return sum;

} ỵ **

* Lấy về số lượng tàikhoản trong ngânhàng

* ©return: trả vềsốlượng tài khoản

7

public int size() {

return accounts.length;

} }

Một phần của tài liệu Bài Giảng Lập Trình Java - Đại Học Thủy Lợi.pdf (Trang 387 - 392)

Tải bản đầy đủ (PDF)

(408 trang)