Giáo trình Lập trình Java (Phần 2)

Một phần tử (element) GUI được thiết lập bằng cách sử dụng thủ tục sau:

 Tạo đối tượng

 Xác định sự xuất hiện ban đầu của đối tượng

 Chỉ ra nó nằm ở đâu

 Thêm phần tử vào giao diện trên màn hình

Một thành phần (component) GUI là một đối tượng trực quan. Người dùng tương

tác với đối tượng này thông qua con trỏ chuột hay bàn phím. Các thành phần như là

button, label có thể được nhìn thấy trên màn hình. Bất kỳ cái gì chung cho tất cả

các thành phần GUI đều được tìm thấy trong lớp Component. Để tạo các đối tượng

GUI chúng ta cần nhập gói java.awt.

AWT là viết tắt của Abstract Windowing Toolkit. AWT là một bộ các lớp trong

Java cho phép chúng ta tạo GUI và chấp nhận các nhập liệu của người dùng thông qua

bàn phím và chuột. AWT cung cấp các thành phần khác nhau để tạo GUI hiệu quả và

lôi cuốn người sử dụng. Các thành phần này có thể là:

 Vật chứa (Container)

 Thành phần (Component)

 Trình quản lý cách trình bày (Layout manager)

 Đồ họa (Graphic) và các tính năng vẽ (draw)

 Phông chữ (Font)

 Sự kiện (Event)

Gói AWT chứa các lớp, giao diện và các gói khác. Hình sau đây mô tả một phần

nhỏ của hệ thống phân cấp lớp AWT.

 

Giáo trình Lập trình Java (Phần 2) trang 1

Trang 1

Giáo trình Lập trình Java (Phần 2) trang 2

Trang 2

Giáo trình Lập trình Java (Phần 2) trang 3

Trang 3

Giáo trình Lập trình Java (Phần 2) trang 4

Trang 4

Giáo trình Lập trình Java (Phần 2) trang 5

Trang 5

Giáo trình Lập trình Java (Phần 2) trang 6

Trang 6

Giáo trình Lập trình Java (Phần 2) trang 7

Trang 7

Giáo trình Lập trình Java (Phần 2) trang 8

Trang 8

Giáo trình Lập trình Java (Phần 2) trang 9

Trang 9

Giáo trình Lập trình Java (Phần 2) trang 10

Trang 10

Tải về để xem bản đầy đủ

pdf 119 trang duykhanh 4920
Bạn đang xem 10 trang mẫu của tài liệu "Giáo trình Lập trình Java (Phần 2)", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình Lập trình Java (Phần 2)

Giáo trình Lập trình Java (Phần 2)
ln(" "); 
 } 
 } 
 class Source implements Runnable{ 
 int number; 
 Target target; 
 Thread t; 
 238 
 public Source(Target targ,int n){ 
 target = targ; 
 number = n; 
 t = new Thread(this); 
 t.start(); 
 } 
 // đồng bộ gọi phương thức display() 
 public void run(){ 
 synchronized(target) { 
 target.display(number); 
 } 
 } 
} 
class Synchblock { 
 public static void main(String args[]){ 
 Target target = new Target(); 
 int digit = 10; 
 Source s1 = new Source(target,digit++); 
 Source s2 = new Source(target,digit++); 
 Source s3 = new Source(target,digit++); 
 try{ 
 s1.t.join(); 
 s2.t.join(); 
 s3.t.join(); 
 }catch(InterruptedException e){ 
 System.out.println("Interrupted"); 
 } 
 } 
} 
 239 
 Ở đây, từ khóa synchronized không hiệu chỉnh phương thức “display()”. Từ khóa 
này được sử dụng trong phương thức run() của lớp “Target”. Kết quả xuất ra màn hình 
tương tự với kết quả chỉ ra ở hình số 6.6 
6.10.3. Ƣu điểm của các phƣơng thức đồng bộ 
 Người lập trình thường viết các chương trình đơn luồng. Tất nhiên một số trường 
hợp nhất định đa luồng là không hiệu quả. Ví dụ nó không làm tăng hiệu năng của các 
trình biên dịch. Trình biên dịch Java Sun không chứa nhiều phương thức đồng bộ. 
 Các phương thức đồng bộ không thực thi tốt như là các phương thức không đồng 
bộ. Các phương thức này chậm hơn từ ba đến bốn lần so với các phương thức tương 
ứng không đồng bộ. Trong trường hợp chúng ta cần hiệu năng cao thì nên hạn chế sử 
dụng các phương thức đồng bộ. 
6.11. Cơ chế đợi thông báo 
 Luồng chia các tác vụ thành các đơn vị cụ thể và logic. Điều này thay thế các 
hình thức lập trình lặp sự kiện. Các luồng loại trừ “polling” (kiểm tra liên tục). 
 Một vòng lặp dùng để kiểm tra điều kiện gọi là “polling”. Khi điều kiện nhận giá 
trị là True (đúng), các câu lệnh tương ứng được thực hiện. Đây là tiến trình thường 
lãng phí thời gian của CPU. Ví dụ khi một luồng sinh ra một số dữ liệu và các luồng 
khác đang chi phối nó luồng sinh ra phải đợi cho đến khi các luồng sử dụng nó hoàn 
thành trước khi phát sinh ra dữ liệu. 
 Để tránh trường hợp polling, Java bao gồm một cơ chế giao tiếp giữa các tiến 
trình bằng các phương thức “wait()”, “notify()” và “notifyAll()” . Các phương thức 
này được thực hiện như là các phương thức final trong lớp Object, vì vậy tất cả các lớp 
có thể thâm nhập chúng. Tất cả 3 phương thức này có thể được gọi chỉ từ trong phạm 
vi một phương thức đồng bộ (synchronized). 
 Các chức năng của phương thức “wait()”, “notify()”, và “notifyAll()” là: 
  Phương thức wait() làm cho luồng gọi nó từ bỏ yêu cầu monitor, và chuyển 
 sang trạng thái “sleep” (chờ) cho đến khi luồng khác thôi monitor tài nguyên 
 nó cần (đối tượng đang monitor gọi phương thức “notify()”). 
  Phương thức notify() đánh thức, hoặc thông báo cho luồng đầu tiên mà đã 
 gọi phương thức wait() trên cùng đối tượng. 
  Phương thức notifyAll() đánh thức, hoặc thông báo tất cả các luồng mà đã 
 gọi phương thức wait() trên cùng đối tượng. 
  Luồng có quyền ưu tiên cao nhất là luồng chạy đầu tiên. 
 Cú pháp của 3 phương thức này như sau: 
 240 
 final void wait() throws IOException 
 final void notify() 
 final void notifyAll() 
 Các phương thức wait() và notify() cho phép chia sẻ đối tượng, làm tạm ngừng 
luồng, khi đối tượng trở thành không còn giá trị cho luồng. Chúng cũng cho phép 
luồng tiếp tục khi thích hợp. 
 Các luồng bản thân nó không bao giờ kiểm tra trạng thái của đối tượng đã chia 
sẻ. 
 Một đối tượng mà điều khiển các luồng yêu cầu nó theo kiểu này được gọi là 
monitor. Trong phạm vi Java, một monitor là bất kỳ đối tượng nào mà có mã đồng bộ. 
Các monitor được sử dụng cho các phương thức wait() và notify(). Cả hai phương thức 
này phải được gọi trong mã đồng bộ. 
 Một số điểm cần nhớ trong khi sử dụng phương thức wait(): 
  Luồng gọi trả CPU 
  Luồng gọi mở khóa 
  Luồng gọi đi vào vùng đợi của monitor. 
 Các điểm chính cần nhớ về phương thức notify() 
  Một luồng vùng đợi của monitor chuyển sang trạng thái sẵn sàng. 
  Luồng mà đã được thông báo phải yêu cầu khóa monitor trước khi nó có 
 thể bắt đầu. 
  Phương thức notify() là không chính xác, vì nó không thể chỉ ra được luồng 
 được thông báo. Trong một trạng thái đã trộn lẫn, luồng có thể thay đổi 
 trạng thái của monitor mà điều này làm ảnh hưởng đến luồng đã được đưa 
 thông báo. Trong trường hợp này, các phương thức của monitor đưa ra 2 sự 
 đề phòng: 
 o Trạng thái của monitor sẽ được kiểm tra trong một vòng lặp “while” 
 thay vì là câu lệnh if 
 o Sau khi thay đổi trạng thái của monitor, phương thức notifyAll() nên 
 được sử dụng thay vì notify(). 
 Ví dụ 6.7: Biểu thị cho việc sử dụng các phương thức notify(0 và wait(): 
 import java.applet.*; 
 import java.awt.*; 
 import java.awt.event.*; 
 /* */ 
 public class mouseApplet extends Applet implements MouseListener{ 
 boolean click; 
 241 
 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) { 
 } 
 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); 
 242 
 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 
 } 
 Không cần các phương thức wait() và notify(), 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 6.7. Kết quả sau mỗi lần kích chuột 
 243 
6.12. Khoá chết (Deadlock) 
 Một “deadlock” xảy ra khi hai luồng có một phụ thuộc vòng trên một cặp đối 
tượng đồng bộ; 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” khoá chết xảy ra. 
 Khó để tìm ra khóa chế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 thực thi cùng lúc 
  Nó liên quan đến nhiều hơn hai luồng và hai đối tượng đồng bộ 
 Nếu một chương trình đa luồng bị treo thường xuyên, ngay lập tức kiểm tra lại 
điều kiện gây ra khoá chết. 
 Ví dụ 6.8:sau tạo ra điều kiện khoá chết. Lớp chính bắt đầu 2 luồng. Mỗi luồng 
gọi phương thức đồng bộ run(). Khi luồng “t1” thức dậy, nó gọi phương thức 
“synchIt()” của đối tượng deadlock “dlk2”. Khi luồng “t1” monitor “dlk2”, luồng “t1” 
bắt đầu đợi monitor. Khi luồng “t2” thức, nó cố gắng gọi phương thức “synchIt()” của 
đối tượng Deadlock “dlk1”. 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ẽ không bao 
giờ thức được. Đây là điều kiện khoá chết. 
 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 = dlk2; 
 dlk2.grabIt = dlk1; 
 t1.start(); 
 t2.start(); 
 System.out.println("Started"); 
 try{ 
 t1.join(); 
 t2.join(); 
 }catch(InterruptedException e){ 
 System.out.println("error occured"); 
 244 
 } 
 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: 
 245 
 Hình 6.8. Kết quả thực hiện ví dụ 6.8 
6.13. Thu dọn rác 
 Thu dọn “rác” (Garbage collection) cải tạo hoặc làm trống bộ nhớ đã cấp 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 tự giải phóng. Thất bại 
trong việc giải phóng bộ nhớ có thể gây ra một số hậu quả. Java tự động tiến hành thu 
dọn rác để cung cấp giải pháp 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ó được gán bằng null. 
 Trình thực thi dọn rác là một luông chạy ngầm (deamon) co mức ưu tiên thấp. 
Ta có thể gọi phương thức gc() của thể nghiệm để 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 ngay sau đó. 
 Sử dụng câu lệnh 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 
thiếu bộ nhớ. 
 Phƣơng thức finalize() 
 Java cung cấp một phương pháp để làm sạch rác trước khi một luồng, chương 
trình kết thúc. Điều này tương tự như phương thức Destructor của C++ 
 Phương thức finalize(), nếu có, sẽ được thực thi trên mỗi đối tượng, trước khi 
sự dọn rác thực hiện. 
 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à rác; chỉ các đối tượng mới gọi là rác 
 Ví du: 
 Object a = new Object(); 
 246 
 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 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, 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 truy cập 
được, thật vậy, nó vẫn còn có phạm vi sử dụng trong phạm vi chương trình. Ở đây, nó 
sẽ không được dọn. 
 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 việc dọn rác. 
 Object a = new Object(); 
 a = null; 
 Một ví dụ khác: 
 Object m = new Object(); 
 Object m = null; 
 Đối tượng được tạo ra ban đầu trở thành đối tượng cần dọn cho bộ dọn rác 
 Object m = new Object(); 
 m = new Object(); 
 Bây giờ, ban đầu sẽ được dọn, 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 gc() (garbage collection), nhưng không bảo đảm 
rằng nó sẽ chạy. 
 Ví dụ 6.9: điển hình cho gc(). 
 class GCDemo 
 { 
 public static void main(String args[]) 
 { 
 int i; 
 long a; , 
 247 
 Runtime r=Runtime.getRuntime(); 
 long valuesD =new long[200]; 
 System.out.println("Amount of free memory is" + r.freeMemory()); 
 r.gc(); 
 System.out.println("Amount of free memory after garbage collection is " 
 + r.freeMemory()); 
 for (a=10000,i=0;i<200;a++,i++) 
 { 
 values[i] =new long(a); 
 } 
 System.out.println("Amount of free memory after creating the array 
 " + r.freeMemory()); 
 for (i=0;i<200;i++) 
 { 
 values[i] =null; 
 } 
 System.out.println("Arnount of free memory after garbage collection is 
 " + r.freeMemory()); 
 } 
 } 
 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 xem lượng bộ nhớ trống, và hiển thị nó. 
Rồi thì chúng ta gọi phương thức gc() của đối tượng Runtime hiện thời. Điều này 
không chắc sẽ thực thi dọn rác ngay. Rồi chúng ta tạo ra mảng, và gán 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 phần tử 
mảng trở thành đối tượng cho bộ thu nhặt rác ta gán chúng bằng null. Cuối cùng, 
chúng ta sử dụng phương thức gc() để gọi bộ dọn rác lần nữa. 
 Kết quả xuất ra màn hình của chương trình trên như sau: 
 248 
Hình 6. 9. Kết quả chạy ví dụ 6.9 
 249 
Câu hỏi và bài tập chƣơng 6 
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 đạt 
giá trị 0. Giá trị sẽ được trả lại 300 một lần nữa giảm đến trở thành 0. 
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. 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 xử lý ngoại lệ. 
3. Sử dụng Java Awt, Java Applet, và Thread viết chương trình vẽ một đoạn thẳng 
màu đỏ trên nền đen chuyển động quy trung quanh một tâm cố định theo mẫu ở hình 
sau: 
 250 
4. Sử dụng Java Awt, Java Applet, Thread vẽ ra màn hình dòng chữ “WellCome” màu 
magenta, chạy ngẫu nhiên trên màn hình khi chạm các cạnh sẽ bật trở lại theo mẫu ở 
hình sau: 
5. Sử dụng Java Awt, Java Applet, Thread vẽ ra màn hình dòng chữ “Java Applet” 
màu xanh, chạy từ trái sang phải theo mẫu ở hình sau: 
6. Sử dụng Java Awt, Java Applet, Thread vẽ ra màn hình dòng chữ “Khoa Công Nghệ 
Thông Tin” chạy từ phải sang trái mẫu ở hình sau: 
 251 
7. Sử dụng Java Awt, Java Applet và Thread viết chương trình tạo hình quả bóng 
chuyển động ngẫu nhiên trên màn hình, khi chạm vào các cạnh sẽ bật trở lại theo mẫu 
ở hình sau: 
8. Viết một chương trình cho thấy rằng những Thread có độ ưu tiên cao được thực thi, 
những thread có độ ưu tiên thấp sẽ bị dừng. 
9. Viết một chương trình ví dụ cho một thread có độ ưu tiên cao sử dụng Sleep để cho 
những thread có độ ưu tiên thập sẽ chuyển sang chế độ run. 
10. 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: 
11. Viết một chương trình hiển thị như hình dưới đây: 
 252 
 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. 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 xử lý ngoại lệ. 
 253 
 TÀI LIỆU THAM KHẢO 
[1]. Trần Tiến Dũng. Giáo Trình Lý Thuyết Và Bài Tập Java. NXB Lao động xã hội. 
 2005. 
[2]. Hoàng Đức Hải. Nguyễn Phương Lan. Java Tập 1. NXB Lao động xã hội. 2004. 
[3]. Hoàng Đức Hải. Nguyễn Phương Lan. Java Tập 2. NXB Lao động xã hội. 2004. 
[4]. Hồ Trọng Long. Nguyễn Duy Hoàng Mỹ. Nhập Môn Lập Trình Java. NXB Thống 
 Kê. 2005 
[5]. Đoàn Thiện Ngân. Cấu trúc dữ liệu với Java. Nhà xuất bản Lao động – Xã 
 hội2005 
[6]. Bruce Eckel, Thinking in Java, Prentice-Hall mid-June, 2006. 
[7]. Horstmann and GaryCornell.Core JavaVolume II--Advanced Features (9th 
 Edition) (Core Series). Publisher2013. 
[8]. Michael Ernest. Java SE 7 Programming Essentials, Publisher2013 
[9].  
[10].  
[11].  
 254 

File đính kèm:

  • pdfgiao_trinh_lap_trinh_java_phan_2.pdf