Đối tượng điều kiện

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

V. Đồng bộ thread

V.3Đối tượng điều kiện

Trong trường hợp thread đi vào vựng bảo vệ, nú cần hoàn thành cụng việc để cú thể mở khúa cho cỏc thread khỏc đi vào. Tuy nhiờn, nếu trong đú cụng việc chớnh cần thực hiện bị giới hạn bởi một điều kiện nào đú, chẳng hạn ở đõy, việc gọi transfer() để chuyển tiền chỉ được thực hiện khi số tiền của account gửi lớn hơn số tiền được gửi:

if (bank.getBalance(from) >= amount) bank.transfer(from, to, amount);

Khi cú điều kiện này, một thread cú thể khụng thỏa món và nú khụng thực hiện việc chuyển tiền, tức là cụng việc của nú là khụng hữu ớch. Đến đõy, ta cú thể nghĩ ra một giải phỏp là để thread đợi cho đến khi nú cú đủ tiền để chuyển:

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

bankLock.lock(); try

{

while (accounts[from] < amount) // Đợi cho đến khi tài khoản của nú cú đủ tiền { // đợi . . . } // Chuyển tiền . . . } finally { bankLock.unlock(); } }

Việc đợi ở đõy sẽ kết thỳc khi một thread khỏc chuyển tiền vào cho nú. Tuy nhiờn ta thấy rằng vựng chứa lệnh chuyển tiền lại đang bị khúa bởi chớnh thread này nờn cỏc thread khỏc khụng thể chuyển tiền được. Kết quả là thread này khụng bao giờ thoỏt khỏi tỡnh trạng đợi, chương trỡnh rơi vào deadlock.

Đõy là tỡnh huống mà ta phải sử dụng đối tượng điều kiện: class Bank

{

public Bank()

{ . . .

sufficientFunds = bankLock.newCondition(); }

. . .

private Condition sufficientFunds; }

Nếu phương thức transfer() kiểm tra và thấy rằng nú chưa đủ tiền để chuyển thỡ nú sẽ gọi: sufficientFunds.await();Lỳc này nú sẽ nằm chờ thread khỏc chuyển tiền.

Cú một sự khỏc nhau căn bản giữa một thread đang đợi để khúa (gọi phương thức lock() để đi vào vựng bảo vệ) và thread gọi phương thức await(). Nú sẽ khụng thể mở khúa khi đang nằm trong vựng khúa cho đến khi một thread khỏc gọi signalAll(). Một thread thực hiện xong việc chuyển tiền, nú nờn gọi: sufficientFunds.signalAll() để mở khúa cho cỏc thread đang nằm đợi thỏa món điều kiện đủ tiền. Một khi thread đó thoỏt khỏi tỡnh trạng đợi do await() gõy ra, nú sẽ được chạy tiếp và cố gắng đi vào vựng khúa và bắt đầu từ vị trớ mà nú chờ đợi trước đú - vị trớ gọi phương thức await() và kiểm tra lại điều kiện.

Một phương thức await() nờn được gọi trong một vũng lặp đợi: while (!(đủ tiền))

condition.await();

Nếu khụng cú thread nào gửi signalAll() thỡ thread đang đợi khụng cú cỏch nào chạy tiếp được. Nếu tất cả cỏc thread khỏc đều đang bị chặn, thread gọi await() khụng giả phúng tỡnh trạng này cho một thread nào đú thỡ bản thõn nú cũng bị chặn, chương trỡnh sẽ bị treo.

Vấn đề là khi nào thỡ gọi signalAll()? Nguyờn tắc chung là khi một thread hoàn thành việc thay đổi trạng thỏi đối tượng thỡ nú nờn gọi signalAll(). Ở đõy, sau khi cộng tiền vào cho tài khoản nhận và thỡ signalAll() sẽ được gọi. Việc gọi này sẽ giỳp cỏc thread cũng đang trong tỡnh trạng chờ đợi này khụng bị chặn nữa và tiếp tục cụng việc với một giỏ trị tài khoản cú thể đó bị thay đổi.

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

bankLock.lock(); try

{

while (accounts[from] < amount) sufficientFunds.await(); // Chuyển tiền . . . sufficientFunds.signalAll(); } finally { bankLock.unlock(); } }

Chỳ ý là việc gọi signalAll() khụng phải là kớch hoạt thread bị chặn ngay lập tức. Nú chỉ giải phúng tỡnh trạng bị chặn của cỏc thread khỏc cho đến khi nú kết thỳc đoạn chương trỡnh được bảo vệ. Một phương thức khỏc là sign() chỉ trao khúa cho một thread xỏc định thay vỡ tất cả. Một thread chỉ cú thể gọi cỏc phương thức signalAll(), sign() và await() trong vựng được bảo vệ.

Chỳng ta cú thể kết thỳc phần này bằng một cõu chuyện minh họa: Cú 10 người cựng đến ngõn hàng để chuyển tiền cho nhau, mỗi người chuyển cho một người khỏc trong số 9 người cũn lại. Mỗi thời điểm ngõn hàng chỉ chuyển tiền cho một người, người được gửi tiền sẽ được vào trong ngõn hàng và giữ khúa cổng, 9 người khỏc phải chờ ngoài cổng. Nếu chẳng may người đang thực hiện chuyển số tiền lớn hơn anh ta cú, anh ta sẽ đợi ở trong ngõn hàng (gọi await()) và nộm khúa ra ngoài cổng cho tất cả 9 người kia. Một trong số 9 người ngoài cổng sẽ được đi vào trong ngõn hàng, thực hiện việc chuyển tiền. Sau khi chuyển xong, anh ta thụng bỏo cho tất cả cỏc anh khỏc đang phải đợi trong ngõn hàng là mỡnh vừa chuyển tiền (gọi signalAll()) rồi đi ra ngoài, sau đú những người đang đợi cũng quay ra cổng để đợi đến lượt vào.

Bài tập

1. Viết một chương trỡnh tạo một thread thực hiện việc giải một phương trỡnh bậc 2 với cỏc hệ số cho trước.

2. Viết chương trỡnh song song với 10 thread để cộng 10000 số tự nhiờn liờn tiếp từ 1 đến 10000.

Phụ lục A. Cỏc từ khúa của Java

Từ khúa í nghĩa

abstract Một lớp hoặc phương thức trừu tượng

assert Được sử dụng để định vị lỗi nội bộ chương trỡnh boolean Kiểu boolean

break Thoỏt khỏi lệnh switch hoặc cỏc vũng lặp byte Số nguyờn 1 byte

case Một lựa chon của switch

catch Một mệnh đề của khối Try để bắt một ngoại lệ char Kiểu ký tự Unicode

class Định nghĩa một class const Khụng được sử dụng

continue Tiếp tục tại vị trớ cuối vũng lặp hiện thời default Mệnh đề mặc định của switch

do Phần trờn của vũng lặp do/while double Kiểu số thực floating-number 8 byte else Mệnh đề else của một lệnh if

extends Xỏc định lớp cha của một lớp

final Một hằng số, hoặc một lớp hay phương thức khụng thể bị khai bỏo chống. finally Một phần của khối try mà luụn được thực hiện

float Số thực 4 byte for Một kiểu vũng lặp goto Khụng sử dụng

if Một lệnh điều khiển rẽ nhỏnh

implements Chỉ ra cỏc interfaces mà lớp sẽ cài đặt. import Nhập một package

instanceof Kiểm tra xem đối tượng cú phải là biểu hiện của một lớp int Số nguyờn 4 byte

interface Một kiểu trừu tượng với cỏc phương thức được cài đặt tại cỏc class long Sụ nguyờn 8 byte

Từ khúa í nghĩa

Native a method implemented by the host system

new Cấp phỏt vựng nhớ cho một đối tượng hoặc mảng mới null Một tham chiếu null

package Một gúi cỏc lớp

private a feature that is accessible only by methods of this class

protected a feature that is accessible only by methods of this class, its children, and other classes in the same package

public a feature that is accessible by methods of all classes return returns from a method

short the 16-bit integer type

static a feature that is unique to its class, not to objects of its class strictfp Use strict rules for floating-point computations

super the superclass object or constructor switch a selection statement

synchronized a method or code block that is atomic to a thread

this the implicit argument of a method, or a constructor of this class throw throws an exception

tHRows the exceptions that a method can throw transient marks data that should not be persistent try a block of code that traps exceptions void denotes a method that returns no value

volatile ensures that a field is coherently accessed by multiple threads while a loop

Phụ lục B Một số hàm hay sử dụng

a) Hàm toỏn h c, l p java.lang.Math; {java.math.*;}ọ ớ

1. abs(number x): lấy |x|, x cú thể là cỏc kiểu long, int, float, double. 2. acos(double x) = arccos(x). x từ 0.0 ... PI

3. asin(double x) = arcsin(x). x từ -PI/2 ... PI/2 4. atan(double x) = arctag(x).

5. ceil(double x): làm cận trờn hoặc cận dưới của số x. 6. cos(double x) = cos(x). x là radian.

7. exp(double x) = ex. 8. log(double x) = Ln(x).

9. max(number x, number y) = max{x, y}, trong đú x, y cú thể là kiểu int, float, double, long.

10. min(number x, number y) = min{x, y}, trong đú x, y cú thể là kiểu int, float, double, long.

11. pow(double x, double y) = xy.

12. random(): cho một số ngẫu nhiờn trong [0.0, 1.0].

13. round(number x): làm trũn số x, nếu x là kiểu double thỡ thành kiểu long, nếu x là kiểu float thỡ thành kiểu int.

14. sin(double x) = sin(x). 15. sqrt(double x) = 16. tan(double x) = tg(x).

Khi s d ng ta ph i dựng Math.tờn_hàm.ử ụ ả b) L p String, khai bỏo java.lang.String;ớ

1. String() : Khởi động một đối tượng chuỗi.

2. String(String s) : Khởi động một chuỗi bằng chuỗi s. 3. length() : trả về giỏ trị int là độ dài một chuỗi. 4. charAt(int i): trả về một ký tự thứ sau i.

5. indexOf(int ch): trả về vị trớ trước của ký tự ch đầu tiờn tỡm thấy. 6. concat(String str): nối thờm chuỗi str vào sau.

7. toLowerCase(): thay đổi chuỗi thành chữ thường. 8. toUpperCase(): chuyển đổi chuỗi thành chữ HOA. Lớp Date khai bỏo java.util.Date;

1. Date(): cho thứ, thỏng, ngày, giờ, năm. 2. getDate(): trả về giỏ trị của ngày trong thỏng.

3. getDay(): trả về giỏ trị int là thứ trong tuần, 0 = CN, 1 = mon, ..., 6 = Sat. 4. getMonth(): trả về giỏ trị int là thỏng trong năm (0..11).

5. getYear(): trả về giỏ trị int là năm. Lấy mốc là 1900, năm thực = date.getYear() +1900.

6. getTime(): trả về là một số được tớnh theo giõy đồng hồ. 7. getHours(): trả về giỏ trị int chỉ giờ trong ngày.

8. getMinutes(): trả về giỏ trị int chỉ phỳt trong giờ.

9. getSeconds(): trả về giỏ trị int chỉ giõy đồng hồ trong phỳt. 10. setDate(int date) đặt lại ngày trong biến. date lấy giỏ trị từ 1..31

11. setMonth(int month): thay đổi giỏ trị thỏng trong biến date. month cú giỏ trị 0..11. 12. setYear(int year): thay đổi giỏ trị năm trong biến date. (year + 1900).

13. setHours(int hour): thay đổi giỏ trị giờ trong biến date. 14. setMinutes(int i): thay đổi giỏ trị phỳt trong biến date. 15. setSeconds(int i): thay đổi giỏ trị giõy trong biến date.

Tài liệu tham khảo

[1] Deitel & Associates (2001), “Java, How to program”, fourth edition.

[2] Cay S. Horstmann, Gary Cornell (2004), “Core Java™ 2”, volume 1,2, Prentice Hall PTR [3] David Reilly, Michael Reilly (2002), “Network Programming and Distributed Computing”, Addison Wesley

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