Đồng bộ (Synchronization)

Một phần của tài liệu Bài giảng Ngôn ngữ lập trình Java: Phần 2 - TS. Vũ Hữu Tiến (Trang 33 - 35)

Khi làm việc với đa luồng, chúng ta có thể gặp tình huống nhiều luồng cùng truy cập tới tài nguyên chung, ví dụ như cùng biến hoặc cùng dữ liệu trong cơ sở dữ liệu Trong trường hợp này có thể xảy ra trường hợp xung đột về dữ liệu. Ví dụ một luồng đang đọc dữ liệu trong khi một luồng khác đang thay đổi dữ liệu. Để giải quyết vấn đề này, chúng ta phải đặt ra quy định chỉ cho một luồng truy cập dữ liệu tại một thời điểm. Khi một luồng hoàn thành công việc với dữ liệu thì luồng khác mới có thể truy cập vào dữ liệu. Trong Java, để thực hiện việc này, chúng ta dùng từ khóa “synchronized” để đồng bộ việc truy cập của các luồng.

Ví dụ: Giả sử chúng ta có một biến đếm count và chúng ta cho 2 luồng cùng truy cập vào biến này để tăng giá trị của biến. Sau mỗi lần tăng, chúng ta in giá trị của biến ra. Kết quả mong muốn như sau:

Giả sử chương trình được viết như sau:

Lớp chính:

import java.applet.Applet; import java.awt.Graphics;

public class NewApplet extends Applet { public void init() {

this.setSize(600,200);

Graphics g = getGraphics();

SharedNumber count = new SharedNumber(g); Counter c1 = new Counter(count,"Thread 1"); Counter c2 = new Counter(count,"Thread 2"); c1.start();

c2.start(); }

}

Lớp Counter:

public class Counter extends Thread { private SharedNumber count;

public Counter(SharedNumber count,String name){ super(name);

this.count = count; }

public void run(){

for(int i=1;i<=10;i++){ count.increment();

99

try {

Thread.sleep(1000);

} catch (InterruptedException ex) { Logger.getLogger(Counter.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(this.getName()); } } } Lớp SharedNumber: import java.awt.Graphics; public class SharedNumber { private int n=0; private Graphics g; private int x=1; public SharedNumber(Graphics g){ this.g =g; }

public void increment(){ n = n+1;

g.drawString(n+ ",", x*20,30); x++;

} }

Với chương trình như trên sẽ cho kết quả như sau:

Trong kết quả trên ta thấy một số vị trí bị lỗi khi các giá trị được in ra trên cửa sổ bị trùng nhau về tọa độ. Sở dĩ như vậy vì lý do sau:

- Khi luồng thứ nhất truy cập phương thức increment() và tăng giá trị của biến n lên 1 đơn vị (n=1) và in giá trị của biến n (n=1) tại tọa độ (20,30).

- Luồng thứ hai chiếm quyền sử dụng phương thức increment(). Khi đó giá trị của biến n được tăng lên một đơn vị (n=2), giá trị của biến n được in ra cũng tại tọa độ (20,30) và tăng giá trị x lên một đơn vị (x=2). Chính vì vậy, giá trị 1 và 2 của n bị trùng nhau.

- Luồng thứ nhất tiếp tục sử dụng hàm increment() và tăng giá trị của x tiếp lên một đơn vị (x=3). Sau đó luồng này tiếp tục sử dụng hàm increment() để tăng giá trị n lên một đơn vị và in giá trị n = 3 lên màn hình tại tọa độ (60,30).

100 Chính vì vậy chúng ta thấy hai giá trị n=1 và n=3 được in ra với khoảng cách xa.

- Luồng thứ hai tiếp tục sử dụng hàm increment() và tăng giá trị của n lên 4 và in ra màn hình tại tọa độ (60,30). Chính vì vậy giá trị 3 và 4 được in ra cùng vị trí.

Để tránh việc hai luồng cùng truy cập vào phương thức increment() trong khi luồng kia chưa thực hiện xong phương thức đó, Java cung cấp cơ chế đồng bộ đối với phương thức này. Cụ thể, hàm increment() được khai báo như sau:

public synchronized void increment(){ n = n+1;

g.drawString(n+ ",", x*20,30); x++;

}

Khi đó chúng ta sẽ được kết quả như sau:

Như vậy chúng ta có thể hiểu là từ khóa synchronized trong phần khai báo phương thức giúp cho một luồng được quyền sử dụng toàn bộ các lệnh của phương thức đó xong rồi mới đến lượt các luồng khác được quyển sử dụng phương thức đó.

Một phần của tài liệu Bài giảng Ngôn ngữ lập trình Java: Phần 2 - TS. Vũ Hữu Tiến (Trang 33 - 35)

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

(65 trang)