Core Java - Đa tuyến

¾ Định nghĩa một luồng

¾ Mô tả đa tuyến

¾ Tạo và quản lý luồng

¾ Hiểu được vòng đời của luồng

¾ Mô tảmột luồng hiểm

¾ Giải thích tập hợp các luồng ưu tiên nhưthếnào

¾ Giải thích được sựcần thiết của sự đồng bộ

¾ Hiểu được cách thêm vào các từkhoá synchronized (đồng bộ) nhưthế

nào

¾ Liệt kê những điều không thuận lợi của sự đồng bộ

¾ Giải thích vai trò của các phương thức wait() (đợi), notify() (thông

báo) và notifyAll().

¾ Mô tảmột điều kiện bếtắc (deadlock).

pdf23 trang | Chuyên mục: Java | Chia sẻ: dkS00TYs | Lượt xem: 2238 | Lượt tải: 2download
Tóm tắt nội dung Core Java - Đa tuyến, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
ck; 
 int count; 
public void init() { 
 super.init(); 
 add(new clickArea(this)); //doi tuong ve duoc tao ra va them vao 
 add(new clickArea(this));//doi tuong ve duoc tao ra va them vao 
 addMouseListener(this); 
} 
public void mouseClicked(MouseEvent e) { 
} 
public void mouseEntered(MouseEvent e) { 
56 
} 
public void mouseExited(MouseEvent e) { 
} 
public void mousePressed(MouseEvent e) { 
 synchronized (this) { 
 click = true; 
 notify(); 
 } 
 count++; //dem viec click 
 Thread.currentThread().yield(); 
 click = false; 
} 
 public void mouseReleased(MouseEvent e) { 
 } 
} //kết thúc Applet 
class clickArea extends java.awt.Canvas implements Runnable{ 
 mouseApplet myapp; 
 clickArea(mouseApplet mapp){ 
 this.myapp = mapp; 
 setSize(40,40); 
 new Thread(this).start(); 
 } 
 public void paint(Graphics g){ 
 g.drawString(new Integer(myapp.count).toString(),15,20); 
 } 
 public void run(){ 
 while(true){ 
 synchronized (myapp) { 
 while(!myapp.click){ 
 try{ 
 myapp.wait(); 
 }catch(InterruptedException ie){ 
 } 
 } 
 } 
 repaint(250); 
 } 
 }//end run 
} 
57 
Không cần các phương thức wait() và notify(), luồng bức vẽ (canvas) không thể 
biết khi nào cập nhập hiển thị. Kết quả xuất ra ngoài của chương trình được đưa ra như 
sau: 
Hình 8.8 Kết quả sau mỗi lần kích chuột 
12. Sự bế tắt (Deadlocks) 
 Một “deadlock” (sự bế tắt) xảy ra khi hai luồng có một phụ thuộc vòng 
quanh trên một cặp đối tượng đồng bộ; lấy ví dụ, khi một luồng thâm nhập vào monitor 
trên đối tượng “ObjA”, và một luồng khác thâm nhập vào monitor trên đối tượng “ObjB”. 
Nếu luồng trong “ObjA” cố gắng gọi phương thức đồng bộ trên “ObjB”, một bế tắt xảy 
ra. 
 Nó khó để gỡ lỗi một bế tắt bởi những nguyên nhân sau: 
¾ Nó hiểm khi xảy ra, khi hai luồng chia nhỏ thời gian trong cùng một con 
đường 
¾ Nó có thể bao hàm nhiều hơn hai luồng và hai đối tượng đồng bộ 
 Nếu một chương trình đa tuyến khóa kín thường xuyên, ngay lập tức kiểm tra lại 
điều kiện bế tắt. 
 Chương trình 8.7 tạo ra điều kiện bế tắt. Lớp chính (main) bắt đầu 2 luồng. Mỗi 
luồng gọi phương thức đồng bộ run(). Khi luồng “t1” đánh thức, nó gọi phương thức 
“synchIt()” của đối tượng deadlock “dlk1”. Từ đó luồng “t2” một mình giám sát cho 
“dlk2”, luồng “t1” bắt đầu đợi monitor. Khi luồng “t2” đánh thức, nó cố gắng gọi phương 
thức “synchIt()” của đối tượng Deadlock “dlk2”. Bây giờ, “t2” cũng phải đợi, bởi vì đây 
là trường hợp tương tự với luồng “t1”. Từ đó, cả hai luồng đang đợi lẫn nhau, cả hai sẽ 
đánh thức. Đây là điều kiện bế tắt. 
Chương trình 8.7 
public class Deadlock implements Runnable{ 
 public static void main(String args[]){ 
 Deadlock dlk1= new Deadlock(); 
 Deadlock dlk2 = new Deadlock(); 
 Thread t1 = new Thread(dlk1); 
 Thread t2 = new Thread(dlk2); 
 dlk1.grabIt = dlk1; 
 dlk2.grabIt = dlk2; 
58 
 t1.start(); 
 t2.start(); 
 System.out.println("Started"); 
 try{ 
 t1.join(); 
 t2.join(); 
 }catch(InterruptedException e){ 
 System.out.println("error occured"); 
 } 
 System.exit(0); 
 } 
Deadlock grabIt; 
 public synchronized void run() { 
 try{ 
 Thread.sleep(1500); 
 }catch(InterruptedException e){ 
 System.out.println("error occured"); 
 } 
 grabIt.syncIt(); 
 } 
 public synchronized void syncIt() { 
 try{ 
 Thread.sleep(1500); 
 System.out.println("Sync"); 
 }catch(InterruptedException e){ 
 System.out.println("error occured"); 
 } 
 System.out.println("In the syncIt() method"); 
 } 
} 
Kết quả của chương trình này được hiển thị như sau: 
Hình 8.9 Sự bế tắt 
59 
13. Thu dọn “rác” (Garbage collection) 
 Thu dọn “rác” (Garbage collection) cải tạo hoặc làm trống bộ nhớ đã định vị cho 
các đối tượng mà các đối tượng này không sử dụng trong thời gian dài. Trong ngôn ngữ 
lập trình hướng đối tượng khác như C++, lập trình viên phải làm cho bộ nhớ trống mà đã 
không được yêu cầu trong thời gian dài. Tình trạng không hoạt động để bộ nhớ trống có 
thể là kết quả trong một số vấn đề. Java tự động tiến trình thu dọn rác để cung cấp giải 
pháp duy nhất cho vấn đề này. Một đối tượng trở nên thích hợp cho sự dọn rác nếu không 
có tham chiếu đến nó, hoặc nếu nó đã đăng ký rỗng. 
 Sự dọn rác thực thi như là một luồng riêng biệt có quyền ưu tiên thấp. Bạn có thể 
viện dẫn một phương thức gc() của thể nghiệm để viện dẫn sự dọn rác. Tuy nhiên, bạn 
không thể dự đoán hoặc bảo đảm rằng sự dọn rác sẽ thực thi một cách trọn vẹn sau đó. 
 Sử dụng câu lện sau để tắt đi sự dọn rác trong ứng dụng: 
 Java –noasyncgc …. 
 Nếu chúng ta tắt đi sự dọn rác, chương trình hầu như chắc chắn rằng bị treo do 
bởi việc đó. 
1. Phương thức finalize() (hoàn thành) 
 Java cung cấp một con đường để làm sạch một tiến trình trước khi điều khiển trở 
lại hệ điều hành. Điều này tương tự như phương thức phân hủy của C++ 
 Phương thức finalize(), nếu hiện diện, sẽ được thực thi trên mỗi đối tượng, trước 
khi sự dọn rác. 
 Câu lệnh của phương thức finalize() như sau: 
 protected void finalize() throws Throwable 
 Tham chiếu không phải là sự dọn rác; chỉ các đối tượng mới được dọn rác 
 Lấy thể nghiệm: 
 Object a = new Object(); 
 Object b = a; 
 a = null; 
 Ở đây, nó sẽ sai khi nói rằng “b” là một đối tượng. Nó chỉ là một đối tượng tham 
chiếu. Hơn nữa, trong đoạn mã trích trên mặc dù “a’ được đặt là rỗng, nó không thể được 
dọn rác, bởi vì nó vẫn còn có một tham chiếu (b) đến nó. Vì thế “a” vẫn còn với đến 
được, thật vậy, nó vẫn còn có phạn vi sử dụng trong phạm vi chương trình. Ở đây, nó sẽ 
không được dọn rác. 
 Tuy nhiên, trong ví dụ cho dưới đây, giả định rằng không có tham chiếu đến “a” 
tồn tại, đối tượng “a” trở nên thích hợp cho garbage collection. 
 Object a = new Object(); 
 … 
 … 
 … 
 a = null; 
 Một ví dụ khác: 
 Object m = new Object(); 
 Object m = null; 
60 
 Đối tượng được tạo ra trong sự bắt đầu có hiệu lực cho garbage collection 
 Object m = new Object(); 
 M = new Object(); 
 Bây giờ, đối tượng căn nguyên có hiệu lực cho garbage collection, và một đối 
tượng mới tham chiếu bởi “m” đang tồn tại. 
 Bạn có thể chạy phương thức garbage collection, nhưng không có banỏ đảm rằng 
nó sẽ xảy ra. 
 Chương trình 8.8 điển hình cho garbage collection. 
 Chương trình 8.8 
 class GCDemo 
{ 
public static void main(String args[]) 
{ 
int i; 
long a; , 
Runtime r=Runtime.getRuntimeO; 
Long valuesD =new Long[200]; 
System. out. print In ("Amount of free memory is" + 
r.freeMemoryO); 
r.gcO; 
System.out.println("Amount of free memory after garbage 
collection is " + r.freeMemoryO); 
for (a=IOOOO.i=O;i<200;a++.i++) 
{ 
values[i] =new Long(a); 
} 
System.out.println("Amount of free memory after creating the array 
" + r.freeMemoryO); 
for (i=O;i<200;i++) 
{ 
values[i] =null; 
} 
System.out.println("Arnount of free memory after garbage collection is 
" + r.freeMemoryO); 
} 
 Chúng ta khai một mảng gồm 200 phần tử, trong đó kiểu dữ liệu là kiểu Long. 
Trước khi mảng được tạo ra, chúng ta phải xác định rõ số lượng bộ nhớ trống, và hiển thị 
nó. Rồi thì chúng ta viện dẫn phương thức gc() của thể nghiệm Runtime (thời gian thực 
thi) hiện thời. Điều này có thể hoặc không thể thực thi garbage collection. Rồi thì chúng 
ta tạo ra mảng, và đang ký giá trị cho các phần tử của mảng. Điều này sẽ giảm bớt số 
lượng bộ nhớ trống. Để làm các mảng phần tử thích hợp cho garbage collection, chúng ta 
đặt chúng rỗng. Cuối cùng, chúng ta sử dụng phương thức gc() để viện dẫn garbage 
collection lần nữa. 
 Kết quả xuất ra màn hình của chương trình trên như sau: 
61 
Hình 8.10 Garbage collection 
 Tổng kết 
¾ Một luồng là đơn vị nhỏ nhất của đoạn mã thực thi được mà một tác vụ riêng 
biệt. 
¾ Đa tuyến giữ cho thời gian rỗi là nhỏ nhất. Điều này cho phép bạn viết các 
chương trình có khả năng sử dụng tối đa CPU. 
¾ Luồng bắt đầu thực thi sau khi phương thức start() được gọi 
¾ Lập trình viên, máy ảo Java, hoặc hệ điều hành bảo đảm rằng CPU được chia 
sẻ giữa các luồng. 
¾ Có hai loại luồng trong một chương trình Java: 
o Luồng người dùng 
o Luồng hiểm. 
¾ Một nhóm luồng là một lớp mà nắm bắt một nhóm các luồng. 
¾ Đồng bộ cho phép chỉ một luồng thâm nhập một tài nguyên được chia sẻ tại 
một thời điểm. 
¾ Để tránh kiểm soát vòng, Java bao gồm một thiết kế tốt trong tiến trình kỹ 
thuật truyền thông sử dụng các phương thức “wait()” (đợi), “notify()” (thông 
báo) và “notifyAll()” (thông báo hết). 
¾ Một “bế tắt” xảy ra khi hai luồng có mọt phụ thuộc xoay vòng trên một phần 
của các đối tượng đồng bộ 
¾ Garbage collection là một tiến trình nhờ đó bộ nhớ được định vị để các đối 
tượng mà không sử dụng trong thời gian dài, có thể cải tạo hoặc làm rãnh bộ 
nhớ. 
Kiểm tra lại sự hiểu biết của bạn 
1. Một ứng dụng có thể chứa đựng nhiều luồng Đúng/Sai 
2. Các luồng con được tạo ra từ luồng chính Đúng/Sai 
3. Mỗi luồng trong một chương trình Java được đăng ký một quyền ưu tiên mà máy 
ảo Java có thể thay đổi. Đúng/Sai 
62 
4. Phương thức____________ có thể tạm thời ngừng việc thực thi luồng 
5. Mặc định, một luồng có một quyền ưu tiên ________ một hằng số của _______ 
6. _________ luồng được dùng cho các luồng “nền”, cung cấp dụch vụ cho luồng 
khác. 
7. Trong luồng đồng bộ, một __________ là một đối tượng mà được sử dụng như là 
một khóa riêng biệt lẫn nhau. 
8. ___________ thường thực thi bởi một vòng lặp mà được sử dụng để lặp lại việc 
kiểm tra một số điều kiện. 
Bài tập: 
1. Viết một chương trình mà hiển thị một sự đếm lùi từng giây cho đến không, như 
hình sau: 
 Ban đầu, số 300 sẽ được hiển thị. Giá trị sẽ được giảm dần cho đến 1 đến khi 
ngoài giá trị 0. Giá trị sẽ được trả lại 300 một lần nữa giảm đến trở thành 0. 
63 
2. Viết một chương trình mà hiển thị như hình dưới đây: 
 Tạo 3 luồng và một luồng chính trong “main”. Thực thi mỗi luồng như một 
chương trình thực thi. Khi chương trình kết thúc, các câu lệnh thoát cho mỗi luồng sẽ 
được hiển thị. Sử dụng kỹ thuật nắm bắt lỗi. 

File đính kèm:

  • pdfUnlock-CoreJava_C8.pdf
Tài liệu liên quan