Lập trình đa luồng Java
Trang 1 trong tổng số 1 trang
Lập trình đa luồng Java
Việc đồng bộ hóa một method là cách tốt nhất để hạn chế việc sử dụng một method tại một thời điểm. Tuy nhiên sẽ có những trường hợp mà bạn không thể đồng bộ hóa một method, chẳng hạn như khi bạn sử dụng một class được cung cấp bởi bên thứ ba. Trong những trường hợp như thế, bạn không được phép truy cập vào định nghĩa lớp, sẽ ngăn bạn sử dụng từ khóa synchronized.
Sử dụng phát biểu được đồng bộ hoá
Một cách khác để sử dụng từ khóa synchronized là sử dụng phát biểu được đồng bộ hóa. Một phát biểu được đồng bộ hóa chứa một block được đồng bộ hóa , mà bên trong đó đặt những đối tượng và những method được đồng bộ hóa. Gọi các method chứa block được đồng bộ hóa xảy ra khi một thread có được monitor của đối tượng.
Mặc dù bạn có thể gọi những method bên trong một block được đồng bộ hóa, việc công bố method phải được thực hiện bên ngoài một block được đồng bộ hóa.
Ví dụ dưới đây chỉ cách làm thế nào để sử dụng một phát biểu được đồng bộ hóa. Ví dụ này cơ bản cũng giống ví dụ trước, tuy nhiên phát biểu được đồng bộ hóa được sử dụng thay vì từ khóa synchronized. Phát biểu này được đặt trong method run() của class MyThread. Phát biểu được đồng bộ hóa sẽ đồng bộ hóa instance của class Parentheses và vì thế ngăn hai thread sử dụng method display() cùng một lúc.
class Parentheses {
void display(String s) {
System.out.print (”(” + s);
try {
Thread.sleep (1000);
} catch (InterruptedException e) {
System.out.println (”Interrupted”);
}
System.out.println(”)”);
}
}
class MyThread implements Runnable {
String s1;
Parentheses p1;
Thread t;
public MyThread (Parentheses p2, String s2) {
p1= p2;
s1= s2;
t = new Thread(this);
t.start();
}
public void run() {
synchronized(p1){
p1.display(s1);
}
}
}
class Demo{
public static void main (String args[]) {
Parentheses p3 = new Parentheses();
MyThread name1 = new MyThread(p3, “Bob”);
MyThread name2 = new MyThread(p3, “Mary”);
try {
name1.t.join();
name2.t.join();
} catch (InterruptedException e ) {
System.out.println( “Interrupted”);
}
}
}
Ở đây, method display() không sử dụng từ khóa synchronized. Thay vào đó, phát biểu được đồng bộ hóa được sử dụng bên trong method run(). Điều này cho kết quả giống với ví dụ trước bởi vì một thread chờ một khoảng thời gian để thread còn lại kết thúc trước khi tiếp tục xử lý.
Giao tiếp giữa các thread
Các thread mở ra cho các lập trình viên một khoảng không mới trong lập trình, nơi mà ở đó những phần của một chương trình thực thi không đồng bộ với nhau, mỗi một xử lý độc lập với những xử lý khác. Tuy nhiên mỗi thread thỉnh thoảng cần tính toán việc xử lý của chúng và vì thế cần có thể giao tiếp với những thread khác trong suốt quá trình xử lý. Các lập trình viên gọi đây là inter-process communication (giao tiếp trong xử lý).
Bạn có thể có các thread giao tiếp với các thread khác trong chương trình của bạn bằng cách sử dụng những method wait(), notify() và notifyAll(). Những method này được gọi từ bên trong một method được đồng bộ hóa. Method wait() nói cho một thread giải phóng monitor và đi vào trạng thái suspend. Có hai dạng method wait() khác nhau. Một dạng không yêu cầu đối số và vì thế một thread sẽ chờ cho đến khi nó được thông báo. Một dạng khác có đối số để bạn xác định khoảng thời gian chờ. Bạn xác định độ dài thời gian trong mili giây và đặt nó vào trong method wait().
Method notify() nói cho một thread đang suspend bởi method wait() và lấy lại điều khiển của monitor. Method notifyAll() đánh thức tất cả các thread đang chờ điều khiển của monitor. Những thread khác chờ trong trạng thái suspend cho đến khi monitor có sẵn trở lại.
Ví dụ dưới đây chỉ cho bạn làm thế nào để sử dụng những method này trong một ứng dụng. Mục đích của chương trình là có một class Pulishser cho một giá trị cho class Consumer thông qua sử dụng class Queue. Ví dụ này định nghĩa bốn class, class Pulisher, class Comsumer, class Queue và class Demo. Class Queue định nghĩa hai instance: exchangeValue và một biến cờ. exchangeValue đặt vào một giá trị trong queue bởi publisher. Biến cờ được sử dụng như một cách đánh dấu giá trị được đặt vào trong queue. Class Queue cũng định nghĩa một method get() và một method put(). Method put() sử dụng để đặt một giá trị vào queue (gán một giá trị cho exchangeValue), method get() sử dụng để nhận giá trị chứa trong queue (trả về giá trị của exchangeValue. Khi một giá trị được gán, method put() thay đổi giá trị của biến cờ từ false thành true xác định một giá trị được đặt vào trong queue. Chú ý giá trị của biến cờ được sử dụng như thế nào trong method get() và method put() để có thread gọi method chờ cho đến khi có một giá trị trong queue hoặc không có giá trị nào trong queue, phụ thuộc vào method nào đang được gọi.
Class Publisher công bố một instance của class Queue và sau đó gọi method put() đặt vào năm số nguyên integer trong queue. Mặc dù method put() được đặt trong một vòng lặp for, mỗi số nguyên integer được đặt vào trong queue, và sau đó có một khoảng tạm dừng cho đến khi số nguyên integer được nhận bởi class Consumer.
Class Consumer tương tự như thiết kế class Publisher, ngoại trừ class Consumer gọi method get() năm lần bên trong một vòng lặp for. Mỗi lần gọi, method get() tạm dừng cho đến khi class Publisher đặt một số nguyên integer vào trong queue.
Method main() của class Demo tạo ra các instance của class Publisher, class Consumer và class Queue. Chú ý rằng các khởi dựng của của class Publisher và class Consumer đều đặt vào một reference đến instance của class Queue. Chúng sử dụng instance của class Queue cho inter-process communication.
Dưới đây là những gì mà bạn sẽ thấy khi chạy chương trình và mã nguồn của ví dụ
Put: 0
Get: 0
Put: 1
Get: 1
Put: 2
Get: 2
Put: 3
Get: 3
Put: 4
Get: 4
class Queue {
int exchangeValue;
boolean busy = false;
synchronized int get() {
if (!busy)
try {
wait();
} catch (InterruptedException e) {
System.out.println(
“Get: InterruptedException”);
}
System.out.println(”Get: ” + exchangeValue);
notify();
return exchangeValue;
}
synchronized void put (int exchangeValue) {
if (busy)
try {
wait();
} catch (InterruptedException e) {
System.out.println(
“Put: InterruptedException”);
}
this.exchangeValue = exchangeValue;
busy = true;
System.out.println(”Put: ” + exchangeValue);
notify();
}
}
class Publisher implements Runnable {
Queue q;
Publisher(Queue q) {
this.q = q;
new Thread (this, “Publisher”).start();
}
public void run() {
for (int i = 0; i < 5; i++){
q.put(i);
}
}
}
class Consumer implements Runnable {
Queue q;
Consumer (Queue q) {
this.q = q;
new Thread (this, “Consumer”).start();
}
public void run() {
for (int i = 0; i < 5; i++){
q.get();
}
}
}
class Demo {
public static void main(String args []) {
Queue q = new Queue ();
new Publisher (q);
new Consumer (q);
}
}
Sử dụng phát biểu được đồng bộ hoá
Một cách khác để sử dụng từ khóa synchronized là sử dụng phát biểu được đồng bộ hóa. Một phát biểu được đồng bộ hóa chứa một block được đồng bộ hóa , mà bên trong đó đặt những đối tượng và những method được đồng bộ hóa. Gọi các method chứa block được đồng bộ hóa xảy ra khi một thread có được monitor của đối tượng.
Mặc dù bạn có thể gọi những method bên trong một block được đồng bộ hóa, việc công bố method phải được thực hiện bên ngoài một block được đồng bộ hóa.
Ví dụ dưới đây chỉ cách làm thế nào để sử dụng một phát biểu được đồng bộ hóa. Ví dụ này cơ bản cũng giống ví dụ trước, tuy nhiên phát biểu được đồng bộ hóa được sử dụng thay vì từ khóa synchronized. Phát biểu này được đặt trong method run() của class MyThread. Phát biểu được đồng bộ hóa sẽ đồng bộ hóa instance của class Parentheses và vì thế ngăn hai thread sử dụng method display() cùng một lúc.
class Parentheses {
void display(String s) {
System.out.print (”(” + s);
try {
Thread.sleep (1000);
} catch (InterruptedException e) {
System.out.println (”Interrupted”);
}
System.out.println(”)”);
}
}
class MyThread implements Runnable {
String s1;
Parentheses p1;
Thread t;
public MyThread (Parentheses p2, String s2) {
p1= p2;
s1= s2;
t = new Thread(this);
t.start();
}
public void run() {
synchronized(p1){
p1.display(s1);
}
}
}
class Demo{
public static void main (String args[]) {
Parentheses p3 = new Parentheses();
MyThread name1 = new MyThread(p3, “Bob”);
MyThread name2 = new MyThread(p3, “Mary”);
try {
name1.t.join();
name2.t.join();
} catch (InterruptedException e ) {
System.out.println( “Interrupted”);
}
}
}
Ở đây, method display() không sử dụng từ khóa synchronized. Thay vào đó, phát biểu được đồng bộ hóa được sử dụng bên trong method run(). Điều này cho kết quả giống với ví dụ trước bởi vì một thread chờ một khoảng thời gian để thread còn lại kết thúc trước khi tiếp tục xử lý.
Giao tiếp giữa các thread
Các thread mở ra cho các lập trình viên một khoảng không mới trong lập trình, nơi mà ở đó những phần của một chương trình thực thi không đồng bộ với nhau, mỗi một xử lý độc lập với những xử lý khác. Tuy nhiên mỗi thread thỉnh thoảng cần tính toán việc xử lý của chúng và vì thế cần có thể giao tiếp với những thread khác trong suốt quá trình xử lý. Các lập trình viên gọi đây là inter-process communication (giao tiếp trong xử lý).
Bạn có thể có các thread giao tiếp với các thread khác trong chương trình của bạn bằng cách sử dụng những method wait(), notify() và notifyAll(). Những method này được gọi từ bên trong một method được đồng bộ hóa. Method wait() nói cho một thread giải phóng monitor và đi vào trạng thái suspend. Có hai dạng method wait() khác nhau. Một dạng không yêu cầu đối số và vì thế một thread sẽ chờ cho đến khi nó được thông báo. Một dạng khác có đối số để bạn xác định khoảng thời gian chờ. Bạn xác định độ dài thời gian trong mili giây và đặt nó vào trong method wait().
Method notify() nói cho một thread đang suspend bởi method wait() và lấy lại điều khiển của monitor. Method notifyAll() đánh thức tất cả các thread đang chờ điều khiển của monitor. Những thread khác chờ trong trạng thái suspend cho đến khi monitor có sẵn trở lại.
Ví dụ dưới đây chỉ cho bạn làm thế nào để sử dụng những method này trong một ứng dụng. Mục đích của chương trình là có một class Pulishser cho một giá trị cho class Consumer thông qua sử dụng class Queue. Ví dụ này định nghĩa bốn class, class Pulisher, class Comsumer, class Queue và class Demo. Class Queue định nghĩa hai instance: exchangeValue và một biến cờ. exchangeValue đặt vào một giá trị trong queue bởi publisher. Biến cờ được sử dụng như một cách đánh dấu giá trị được đặt vào trong queue. Class Queue cũng định nghĩa một method get() và một method put(). Method put() sử dụng để đặt một giá trị vào queue (gán một giá trị cho exchangeValue), method get() sử dụng để nhận giá trị chứa trong queue (trả về giá trị của exchangeValue. Khi một giá trị được gán, method put() thay đổi giá trị của biến cờ từ false thành true xác định một giá trị được đặt vào trong queue. Chú ý giá trị của biến cờ được sử dụng như thế nào trong method get() và method put() để có thread gọi method chờ cho đến khi có một giá trị trong queue hoặc không có giá trị nào trong queue, phụ thuộc vào method nào đang được gọi.
Class Publisher công bố một instance của class Queue và sau đó gọi method put() đặt vào năm số nguyên integer trong queue. Mặc dù method put() được đặt trong một vòng lặp for, mỗi số nguyên integer được đặt vào trong queue, và sau đó có một khoảng tạm dừng cho đến khi số nguyên integer được nhận bởi class Consumer.
Class Consumer tương tự như thiết kế class Publisher, ngoại trừ class Consumer gọi method get() năm lần bên trong một vòng lặp for. Mỗi lần gọi, method get() tạm dừng cho đến khi class Publisher đặt một số nguyên integer vào trong queue.
Method main() của class Demo tạo ra các instance của class Publisher, class Consumer và class Queue. Chú ý rằng các khởi dựng của của class Publisher và class Consumer đều đặt vào một reference đến instance của class Queue. Chúng sử dụng instance của class Queue cho inter-process communication.
Dưới đây là những gì mà bạn sẽ thấy khi chạy chương trình và mã nguồn của ví dụ
Put: 0
Get: 0
Put: 1
Get: 1
Put: 2
Get: 2
Put: 3
Get: 3
Put: 4
Get: 4
class Queue {
int exchangeValue;
boolean busy = false;
synchronized int get() {
if (!busy)
try {
wait();
} catch (InterruptedException e) {
System.out.println(
“Get: InterruptedException”);
}
System.out.println(”Get: ” + exchangeValue);
notify();
return exchangeValue;
}
synchronized void put (int exchangeValue) {
if (busy)
try {
wait();
} catch (InterruptedException e) {
System.out.println(
“Put: InterruptedException”);
}
this.exchangeValue = exchangeValue;
busy = true;
System.out.println(”Put: ” + exchangeValue);
notify();
}
}
class Publisher implements Runnable {
Queue q;
Publisher(Queue q) {
this.q = q;
new Thread (this, “Publisher”).start();
}
public void run() {
for (int i = 0; i < 5; i++){
q.put(i);
}
}
}
class Consumer implements Runnable {
Queue q;
Consumer (Queue q) {
this.q = q;
new Thread (this, “Consumer”).start();
}
public void run() {
for (int i = 0; i < 5; i++){
q.get();
}
}
}
class Demo {
public static void main(String args []) {
Queue q = new Queue ();
new Publisher (q);
new Consumer (q);
}
}
leanhhuy (I11C)- Tổng số bài gửi : 22
Join date : 30/08/2011
Similar topics
» Giới thiệu về Threads-lập trình đa luồng trong Java
» Thảo luận Bài 5 (Đa luồng)
» Lập trình đa luồng trong Java
» Thảo luận Bài 5
» tổng hợp Đa Luồng : tài liệu tham khảo về Luồng Windows 2000 và Luồng Linux và Luồng Java
» Thảo luận Bài 5 (Đa luồng)
» Lập trình đa luồng trong Java
» Thảo luận Bài 5
» tổng hợp Đa Luồng : tài liệu tham khảo về Luồng Windows 2000 và Luồng Linux và Luồng Java
Trang 1 trong tổng số 1 trang
Permissions in this forum:
Bạn không có quyền trả lời bài viết