Tìm Hiểu Về Synchronized Trong Java

Tìm Hiểu Về Synchronized Trong Java

Ngày này, Thread Programming đang được sử dụng rộng rãi do nhiều lợi ích của nó mang lại. Tuy nhiên một vấn đề lớn của Thread Programming đó là vấn đề đồng bộ hoá hay synchronization. Để hiểu rõ hơn về điều này thì chúng ta cùng tham khảo một ví dụ cụ thể sau.

Trước tiên trong ứng dụng chúng ta có một lớp là CustomerBankAccount dùng để quản lý số tiền gửi Ngân Hàng của khách hàng:

public class CustomerBankAccount {
    private int balance = 0;

    public void deposit(amount) { // gửi tiền
        ballance += amount;
    }

    public void withdraw(amount) { // rút tiền hoặc chuyển khoản
        if (ballance > amount)
            ballance -= amount;
    }

    public int getBalance() {
        return ballance;
    }
}

Ở class trên thì:

  • Thuộc tính balance là số tiền gửi hiện có trong tài khoản.
  • Phương thức deposit() dùng để giảm số tiền gửi khi khách hàng gửi thêm tiền vào tài khoản.
  • Phương thức withdraw() dùng để giảm số tiền gửi khi khách hàng rút tiền từ tài khoản.
  • Phương thước getBallance() dùng để lấy về số tiền trong tài khoản.

Do Ngân Hàng có quá nhiều khách hàng và số lượng giao dịch của khách cũng tăng đáng kể nên để tăng tốc độ xử lý của ứng dụng bạn quyết định sử dụng Multi-Threading thay vì Single-Threading.

Tuy nhiên không lâu sau đó bạn gặp vấn đề đối với loại tài khoản khách hàng doanh nghiệp. Một doanh nghiệp A cấp quyền cho 10 nhân viên của mình có thể thực hiện giao dịch gửi tiền và chuyển tiền từ tài khoản. Chuyện gì xảy ra khi có 10 nhân viên của công ty cùng thực hiện các giao dịch gửi tiền và chuyển tiền vào cùng một thời điểm? Trong trường hợp mỗi giao dịch của một nhân viên được thực hiện trên các Thread khác nhau thì các phương thức deposit() và withdraw() sẽ thực hiện trên các con số balance không khớp nhau.

Cụ thể vào lúc 9h sáng, tài khoản của công ty A có số dư là 10,000$. Sếp công ty này đi ăn nhậu với khách hàng và quyết định rút 2,000$ từ tài khoản. Giao dịch này được xử lý bởi một thead là thread1. Trong khi thread1 đang hoàn tất giao dịch của và vẫn chưa kết thúc thì Kế Toán Trưởng công ty A bắt đầu thực hiện việc kiểm tra số dư tài khoản và thực hiện một giao dịch chuyển khoản ứng tiền 9,000$ cho khách hàng. Giao dịch thứ 2 được thực hiện bởi thread2.

Lúc này do thread1 chưa kết thúc lên thread2 nên vẫn trả về số dư là 10.000$ và Kế Toán Trưởng giao dịch rút tiền 9,000$ của anh ta thực hiện thành công. Đồng thời khi thread1 thực hiện giao dịch thì số tiền dư vẫn lớn hơn 2.000$ nên Sếp công ty A vẫn có thể rút được tiền. Lúc này Ngân Hàng sẽ mất số tiền 1.000$.

Để giải quyết vấn đề trên chúng ta có thể sử dụng synchronized với các method withdrawdeposit và getBallance():

public class CustomerBankAccount {
    private int balance = 0;

    public synchronized  void deposit(amount) { // gửi tiền
        ballance += amount;
    }

    public synchronized void withdraw(amount) { // rút tiền hoặc chuyển khoản
        if (ballance > amount)
            ballance -= amount;
    }

    public synchronized int getBalance() {
        return ballance;
    }
}

Lúc này thì các phương thức synchronized sẽ chỉ được gọi một lần vào một thời điểm nhất định. Nếu có hai thread cùng gọi phương thức withdraw() thì Java sẽ ưu tiên xử lý ở thread nào tới trước, thread tới sau sẽ bị tạm thời dừng lại cho tới khi thread1 xử lý xong.

10 bình luận