Lập trình mạng nâng cao - Lập trình đa tuyến và mô hình client - Server
Tuyến ma thường là tuyến hỗ trợ môi trường thực thi của các tuyến khác. Ví dụ: garbage collector của Java là một tuyến ma.
Chương trình kết thúc khi tất cả các tuyến không phải tuyến ma kết thúc.
Các phương thức với tuyến ma:
void setDaemon(boolean isDaemon); // đặt tuyến //trở thành tuyến ma
boolean isDaemon(); // kiểm tra tuyến có phải //tuyến ma không
54 trang |
Chia sẻ: nguyenlam99 | Lượt xem: 1222 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Lập trình mạng nâng cao - Lập trình đa tuyến và mô hình client - Server, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
*LẬP TRÌNH ĐA TUYẾN& MÔ HÌNH CLIENT - SERVERMultiThread ProgrammingKhái niệm về threadTạo ra các threadLớp ThreadCài đặt lớp RunnableVòng đời của một ThreadLập lịch cho threadĐồng bộ hóa các thread*Khái niệm về ThreadChương trình tuyến tính: Có một khởi đầuChuỗi các hành động với thứ tự xác địnhMột điểm kết thúcChỉ có duy nhất một lệnh thực thi tại một thời điểm*Khái niệm về threadMột thread cũng bao gồm các đặc điểm của các chương trình tuyến tính.Tuy vậy, bản thân thread không phải là một chương trình: Nó không thể tự chạy, mà phải phụ thuộc vào một chương trình*Thread: Định nghĩaMột thread là một dòng điều khiển tuần tự bên trong một chương trình. Lý do sử dụng thread:Trong một chương trình có thể có nhiều thread chạy đồng thời, thực thi các tác vụ khác nhau.*Sử dụng nguồn tài nguyên được cấp phát cho tiến trình và nguồn tài nguyên chung trong chương trình (đồng bộ hóa tiến trình). MultiThread ProgrammingKhái niệm về threadTạo ra các threadLớp ThreadCài đặt lớp RunnableVòng đời của một ThreadLập lịch cho threadĐồng bộ hóa các thread*Tạo Thread trong JavaJava cung cấp một giao diện nhất quán cho các thread. Để cài đặt thread:Cài đặt giao diện RunnableDẫn xuất từ lớp Thread, *Dẫn xuất từ lớp Thread Lớp mới tạo có đầy đủ cơ chế của một threadCần phải nạp chồng phương thức Run của lớp Thread.Phương thức run() chứa đoạn mã sẽ được thực hiện tuần tự, nhưng “đồng thời” với các thread khác trong một chương trình.*Dẫn xuất từ lớp Thread (tt)*Ứng dụng lớp SimpleThreadChương trình trên minh họa hoạt động của hai Thread thay phiên nhau (mặc dù các lệnh khởi tạo chúng được viết tuần tự). Ta có thể thêm thread tùy ý.*Phương thức RUN của một ThreadLà phương thức ảo (virtual method)Hoạt động của Thread sẽ kết thúc ngay khi thoát khỏi phương thức runCần thiết lập các điều kiện dừng cho thread trong phương thức runNếu không, để dừng thread, chúng ta cần phải dùng các phương thức khác như stop hoặc destroy*Dùng toàn bộ lớp như một ThreadỨng dụng SwingApplication hiển thị thời gian và thực hiện các tác vụ khác (trong trường hợp này, là đón nhận và xử lý các sự kiện của người dùng).Điều này được thực hiện nhờ vào Thread: đoạn mã cập nhật đồng hồ chạy bên trong thread của riêng nó.Tạo ra một Thread, và sau đó tạo ra một lớp Runnable và gắn vào Thread.Toàn bộ lớp tồn tại bên trong một Thread và dòng thực thi (stream of execution) được bảo trì bởi thread.*Cài đặt giao diện RunnableĐể tạo ra một lớp đối tượng chạy được trong một tiến trình, lớp đối tượng này cài đặt giao diện Runnable.Lớp SwingApplication cài đặt giao diện Runnable và vì vậy, cài đặt phương thức run định nghĩa trong nó.*Cài đặt lớp ClockThreadApplication*Phương thức getTime*MultiThread ProgrammingKhái niệm về threadTạo ra các threadLớp ThreadCài đặt lớp RunnableVòng đời của một ThreadLập lịch cho threadĐồng bộ hóa các thread*Điều kiểm Thread(Thread Control)Lớp Thread cung cấp cho người lập trình các công cụ để điều kiểm Thread1. start2. stop5. sleep6. destroy7. yield8. run9. isAlive *Dừng một ThreadPhương thức stop được sử dụng để dừng một Thread vào bất cứ lúc nào. Tuy nhiên, đây là phương thức không an toàn.Cách làm được khuyến khích là để một Thread “chết tự nhiên”, như phương thức run sau:*Thoát an toàn khỏi ThreadXét lại phương thức run của lớp ClockThreadApplication, để ý hoạt động của nó và điều kiện dừng của vòng lặp*Thoát an toàn khỏi Thread (tt)Đây là một cách sửa đổi đơn giản với phương thức run của lớp ClockThreadApplication.*Thoát an toàn khỏi Thread (tt)Đối với phiên bản đồ họa, điều này đơn giản hơn với việc xử lý sự kiện đóng ứng dụng SwingApplication.*Trạng thái Not Runnable Một thread trở thành Not Runnable khi một trong các điều kiện sau xuất hiện: Phương thức sleep của nó được gọi. Thread gọi phương thức wait để chờ thỏa một điều kiện cụ thể. Thread bị chặn trên các thiết bị nhập/xuất. *Trạng thái Not Runnable (tt) clockThread trong ứng dụng ClockThreadApplication trở nên Not Runnable khi phương thức run gọi sleep trên thread*Trạng thái Not Runnable (tt)Một Thread trong trạng thái Not Runnable sẽ không tiêu tốn bất kỳ nguồn tài nguyên hệ thống nào, ngay cả CPU lúc đó đang rỗi.Vào và thoát khỏi trạng thái Not RunnableNếu một thread đã được đặt vào trạng thái ngủ, nó phải đợi trong thời gian bằng số milli giây đã chỉ định.Nếu một thread đang đợi một điều kiện, thì thread khác phải thông báo với thread đang chờ về sự thay đổi với phương thức notify hoặc notifyAll.Nếu một thread bị khóa trên I/O, thao tác I/O phải hoàn tất. *MultiThread ProgrammingKhái niệm về threadTạo ra các threadVòng đời của một ThreadLập lịch cho threadĐồng bộ hóa các thread*Xử lý đồng thời Thread ?Khi một thread đang chạy, nó sử dụng nguồn tài nguyên dành riêng cho nó. Nếu có nhiều Thread “đang cùng chạy” trên một máy chỉ có một CPU, JVM phải cài đặt một biểu đồ lập lịch để chia sẻ CPU. Mỗi Thread được Hệ điều hành cấp 1 TCB (Thread Control Block) để quản lý (cấp phát tài nguyên) tương tự như tiến trình (process).*Lập lịch cho ThreadSự thực thi của nhiều Thread trên một CPU duy nhất theo một thứ tự nào đó gọi là lập lịch (schedule)Java hỗ trợ thuật toán lập lịch đơn giản: “Theo độ ưu tiên cố định” (fixed-priority scheduling). JVM lên lịch để chạy các Thread Runnable chủ yếu dựa trên độ ưu tiên của nó.Độ ưu tiên của Thread là một giá trị nằm giữa MIN_PRIORITY và MAX_PRIORITY (các hằng số định nghĩa trong lớp Thread, gồm:MAX_PRIORITY: 10MIN_PRIORITY: 0NORM_PRIORITY: 5, default value). *Lập lịch cho ThreadKhi một Thread mới được tạo ra, nó kế thừa độ ưu tiên từ Thread đã tạo ra nó. Để sửa đổi độ ưu tiên của Thread, dùng phương thức setPriority.*MultiThread ProgrammingKhái niệm về threadTạo ra các threadVòng đời của một ThreadLập lịch cho threadĐồng bộ hóa các thread*Producer/Consumer – vấn đề Xét một ví dụ Producer-Consumer đơn giản (nguồn: Java Tutorial của Sun)Các đối tượng trong ví dụ gồm có:Một nhà sản xuất, đối tượng ProducerMột khách hàng tiêu thụ, đối tượng ConsumerMột đối tượng trung gian đóng vai trò nhà phân phối, đối tượng CubbyHoleHoạt động: nhà sản xuất sẽ sinh một số, giao cho nhà phân phối lưu giữ trong kho của họ (phương thức put). Bên tiêu thụ sẽ nhận số có trong kho này (phương thức get). Yêu cầu bên tiêu thụ mỗi số đúng một lần, và không bỏ sót*Lớp Producer*Lớp Consumer*Lớp CubbyHole*Ứng dụng demo*Start *Điều kiện tranh đuaVấn đề chúng ta vừa gặp thường được gọi là vấn đề tranh đua (race condition).Một race condition là một tình huống mà trong đó hai hoặc nhiều hơn các thread hoặc tiến trình đọc hoặc ghi các dữ liệu chia sẻ.Kết quả cuối cùng tùy thuộc vào thời gian biểu mà theo đó các thread được lập lịch. Các điều kiện tranh đua có thể dẫn đến các kết quả không đoán trước và các lỗi rất khó phát hiện. *Giải pháp – sự đồng bộ hóa Các giải pháp đồng bộ hóa có thể:Cả producer và consumer phải thống nhất với nhau về cách đặt số. Một số sẽ chỉ được lấy ra/đặt vào trong một số điều kiện nào đó.Tổ chức lại lớp CubbyHole như một hàng đợiSử dụng cơ chế đồng bộ hóa của Java với từ khóa synchronized.*Đồng bộ hóa trong JavaCơ chế đồng bộ hóa trong Java cung cấp một tập các công cụ để điều khiển các threads đồng thời chia sẻ một nguồn tài nguyên chung (file hoặc hàng đợi sự kiện chẳng hạn) theo cách tốt đẹp.synchronized Không cho phép cả hai Thread đồng thời truy cập vào một đối tượng (đối tượng bị khóa bởi Thread “nhanh chân”)Các Thread đang đợi một điều kiện (wait) phải được thông báo rằng nó xong việc (qua notify và notifyAll)*Khóa một đối tượngTừ khóa synchronized đặt trong phần khai báo một block (có thể là toàn bộ phương thức) sẽ làm cho đoạn này trở thành vùng tranh chấp (critical section).Khi có một đối tượng truy cập vào một vùng tranh chấp trong một đối tượng, nó sẽ khóa tất cả các vùng tranh chấp khácVì vậy, ta sẽ khai báo hai phương thức put & get là các vùng tranh chấp trong lớp CubbyHole.*Khóa một đối tượng*Khóa một đối tượngVới khai báo trên, khi Producer gọi phương thức put của CubbyHole, nó đồng thời khóa phương thức get, ngăn không cho Consumer gọi; và ngược lại. Tuy vậy,Nếu khóa không sẵn dùng, vẫn có những thiết lập cho phép thread tiếp tục mà không cần phải chờ đợi. Tuy vậy, điều này không được xem xét ở đây. Khi các phương thức của bạn nhận một khóa, hãy chắn chắc rằng nó sẽ trả lại vào lúc nào đó. Bằng không, phần còn lại của ứng dụng sẽ chờ cái khóa mà sẽ chẳng bao giờ được nhả ra cả.*Một trường hợp có thể bị khóa vĩnh viễn*Sử dụng các phương thứcnotifyAll và waitPhương thức get :*Phương thức put:*Sử dụng các phương thứcnotifyAll và waitCác phiên bản khác của waitĐây là hai phiên bản của phương thức wait chứa trong lớp Object: wait() : Chờ đợ vô hạn định các thông báo. (phương thức này được dùng trong ví dụ producer-consumer) wait(long timeout) : Chờ thông báo hoặc cho đến khi thời gian timeout đã trôi qua. timeout được tính theo milliseconds. wait(long timeout, int nanos) : Chờ thông báo hoặc cho đến khi thời gian timeout cộng nanos nanoseconds trôi qua. *Ví dụ: cài đặt Runable*Ví dụ: cài đặt Runableimport java.awt.*;import java.applet.*;public class BallFlying extends Applet implements Runnable{ Thread animThread = null; int ballX= 0, ballY=50; int dx=1, dy=2; boolean stopRun = false; public void start(){ //applet starts if (animThread == null){ animThread= new Thread(this); animThread.start(); } }*Ví dụ: cài đặt Runablepublic void stop(){ // applet stops stopRun = true; } publicvoid run(){ this.setBackground(Color.CYAN); while (! stopRun){ moveBall(); delay(5); } } private void delay(intmiliSeconds){ try{ Thread.sleep(miliSeconds); }catch (Exception e){ System.out.println("Sleeperror !"); } }*Ví dụ: cài đặt Runableprivate void moveBall(){ ballX += dx; ballY += dy; if (ballY> getSize().height -30) dy =- dy; if (ballX> getSize().width -30) dx =- dx; if (ballY< 0) dy =- dy; if (ballX< 0) dx =- dx; repaint(); } publicvoid paint(Graphicsg){ g.fillOval(ballX,ballY, 30, 30); }}*Tuyến ma (daemon thread)Tuyến ma thường là tuyến hỗ trợ môi trường thực thi của các tuyến khác. Ví dụ: garbage collector của Java là một tuyến ma.Chương trình kết thúc khi tất cả các tuyến không phải tuyến ma kết thúc.Các phương thức với tuyến ma:void setDaemon(boolean isDaemon); // đặt tuyến //trở thành tuyến maboolean isDaemon(); // kiểm tra tuyến có phải //tuyến ma không*Lớp TimerHai lớp liên quan tới xử lý công việc theo thời gian:javax.swing.Timerjava.util.TimerLớp java.swing.TimerĐơn giản, dễ dùng trên GUILớp java.util.TimerNhiều tính năng hơn java.swing.Timer*Ví dụ: Đếm ngượcimport java.awt.*;import java.awt.event.*;import java.applet.Applet;public class CountDown extends Applet implements ActionListener{ private TextField timeField; private Button startButton; private Button stopButton; private javax.swing.Timer timer; private int count; public void init(){ timeField = new TextField(6);*Ví dụ: Đếm ngượctimeField.setFont(new Font("sansserif", Font.PLAIN, 18)); startButton = new Button("Start"); stopButton = new Button("Stop"); add(timeField); add(startButton); add(stopButton); startButton.addActionListener(this); stopButton.addActionListener(this); timer = new javax.swing.Timer(10, this); count = 0; } // end init()*Ví dụ: Đếm ngượcpublic void actionPerformed(ActionEvent e){ if (e.getSource() == startButton) timer.start(); else if (e.getSource() == stopButton) timer.stop(); else { count++; int hsecond = count%100; int totalSecond = (count/100); int h = totalSecond/3600; int secondLeft = totalSecond%3600; int m = secondLeft/60; int s = secondLeft%60; timeField.setText("“ + h + ":" + m + ":" + s + ":" + hsecond); } }}*
Các file đính kèm theo tài liệu này:
- chuong_4_lap_trinh_da_tuyen_012.ppt