HƯỚNG DẪN ĐỒNG BỘ HÓA ĐA LUỒNG TRONG JAVA

16-01-2018 10:41

Làm thế nào để có thể đồng bộ hóa đa luồng trong Java trong khi có rất nhiều luồng cùng thực thi? Ngày hôm nay, ITPlus sẽ hướng dẫn các bạn cùng tìm hiểu về cách đồng bộ hóa đa luồng trong Java và trong quá trình hướng dẫn ITPlus cũng sẽ đưa ra một số ví dụ minh họa để các bạn có thể dễ dàng hình dung nhé!

1. Đồng bộ luồng trong Java

Sau đây là một ví dụ đơn giản mà bạn cần phải sử dụng đến đồng bộ giúp các bạn hiểu về đồng bộ luồng trong Java. Ví dụ như sau: Giả sử một công ty cấp quyền cho 10 nhân viên có thể thực hiện giao dịch rút tiền và chuyển tiền từ tài khoản ngân hàng chung của công ty và có số dư tài khoản là 10.000$. Lúc 9h sáng, giám đốc công ty đi giao dịch với khách hàng và rút 2.000$ từ tài khoản. Khi hành động rút tiền của giám đốc đang được thực hiện và chưa kết thúc thì người kế toàn trưởng của công ty bắt đầu thực hiện kiểm tra số dư tài khoản và tiến hàng chuyển tiền cho đối tác của công ty với số tiền là 9.000$.

Vì giao dịch rút tiền của người giám đốc vẫn chưa kết thúc nên khi người kế toán trưởng kiểm tra số dư thì máy ATM vẫn trả với số dư là 10.000$ và giao dịch rút 9.000$ của kế toàn trưởng vẫn được chấp nhận. Trong trường hợp này, nếu không có sự đồng bộ thì cả 2 hành động rút và chuyển tiền đều thực hiện thành công và ngân hàng sẽ mất một số tiền là 1.000$ -> Trường hợp này bắt buộc cần đến sự đồng bộ hóa giữa các luồng.

Nói tóm lại, việc sắp xếp thứ tự các luồng khi truy xuất vào cùng một đối tượng sao cho không có sự xung đột dữ liệu được gọi là đồng bộ luồng trong Java. Khi việc thực thi luồng kết thúc thì luồng khác mới được thực hiện. Đây gọi là cơ chế đồng bộ luồng trong Java.

Để đồng bộ luồng trong Java, chúng ta sẽ sử dụng từ khóa synchronized. Dưới đây là phần trình bày chi tiết.

Các khóa học lập trình 

Khóa học Lập trình website với Java

Khóa học Lập trình Website với ASP.Net

2. Đồng bộ luồng sử dụng từ khóa synchronized

Từ khóa synchronized sẽ đứng trước kiểu trả về và đứng sau phạm vi truy cập của phương thức đó. 

Để minh họa cách sử dụng từ khóa này, có một ví dụ minh họa bài toán ngân hàng như sau:

Customer.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

package dongboluong;

 

public class Customer {

    private int taiKhoan = 10000;

         

    public Customer() {

        System.out.println("Tài khoản hiện có = " + taiKhoan);

    }

         

    private synchronized void rutTien (int soTienRut) {

        System.out.println("Giao dịch rút tiền đang được thực hiện với" +

                " số tiền = " + soTienRut + "...");

         

        if(taiKhoan < soTienRut) {

            System.out.println("Số tiền trong tài khoản không đủ!");

            try {

                wait(); // phương thức wail sẽ đưa Thread rơi vào trạng thái sleeping

            } catch (InterruptedException ie) {

                System.out.println(ie.toString());

            }

        }

         

        taiKhoan -= soTienRut;

        System.out.println("Rút tiền thành công. Số tiền hiện có trong tài khoản = " + taiKhoan);

    }

         

    private synchronized void nopTien(int soTienNop) {

        System.out.println("Giao dịch nộp tiền đang được thực hiện với" +

                " số tiền nộp = " + soTienNop + "...");

        taiKhoan += soTienNop;

        System.out.println("Nộp tiền thành công. Số tiền hiện có trong tài khoản = " + taiKhoan);

        notify();

    }

         

    public static void main(String[] args) {

         

        final Customer customer = new Customer();

         

        Thread t1 = new Thread(){

             

            public void run() {

                customer.rutTien(20000);

            }

             

        };

         

        t1.start();

             

        Thread t2 = new Thread(){

             

            public void run() {

                customer.nopTien(30000);

            }

        };

         

        t2.start();

         

    }

     

}

Kết quả sau khi biên dịch chương trình:

 

 

Giải thích hoạt động của chương trình trên:

Giả sử số tiền hiện có trong tài khoản ngân hàng là 10.000$. Trong hàm main(), ta có 2 luồng: luồng t1 thực hiện việc rút tiền và luồng t2 thực hiện việc nộp tiền vào tài khoản. Trong Thread t1, khách hàng rút 20.000$ thông qua phương thức rutTien(), lúc này số dư trong tài khoản không còn đủ nên hành động rút tiền được đưa vào trạng thái sleeping thông qua dòng lệnh wait(). Sau đó Thread t2 sẽ được thực thi, lúc này khách hàng sẽ nộp vào tài khoản với số tiền là 40.000$ thông qua phương thức nopTien(). Phương thức nopTien() này, khi nộp tiền thành công thì dòng lệnh notify() sẽ đánh thức Thread đứng trước nó đang ở trạng thái sleeping vì phương thức wait() bị gọi. Phương thức rutTien() lúc này sẽ kiểm tra số dư tài khoản là 40.000$> số tiền cần rút là 20.000$ thì hành động rút tiền này sẽ thành công và số dư tài khoản còn lại là 20.000$.

Thiết kế và lập trình web PHP chuyên nghiệp

Lập trình ứng dụng di động Android

Lưu ý: Khi sử dụng phương thức wait(), nếu thấy đoạn try…catch bao bọc bên ngoài thì trong ví dụ này bạn không cần để ý đến nó mà chỉ cần hiểu đây là điều bắt buộc khi cần sử dụng wait().

Trong bài này, ITPlus đã hướng dẫn các bạn tìm hiểu về cách đồng bộ luồng trong Java bằng cách sử dụng từ khóa synchronized. Sẽ còn nhiều kiến thức thú vị dành cho cấc bạn trong các bài sau. Các bạn hãy nhớ theo dõi nhé!

Ban truyền thông ITPlus Academy 

Bài viết cùng chủ đề