Phát triển với Java thời gian thực - Phần 1: Khai thác các đặc tính độc nhất

Tóm tắt: Bộ Java thời gian thực (Real-time Java™) kết hợp dễ dàng việc lập

trình bằng ngôn ngữ Java theo hiệu năng do ứng dụng yêu cầu mà phải phù hợp

với các ràng buộc thời gian thực. Các phần mở rộng của ngôn ngữ Java đưa ra các

đặc tính về môi trường thời gian thực mà đang thiếu trong môi trường thời gian

chạy Java truyền thống. Bài này, bài đầu tiên trong loạt bài ba phần, mô tả một số

đặc tính này và giải thích cách bạn có thể áp dụng chúng để đạt được hiệu năng

thời gian thực trong các ứng dụng của chính mình.

Java thời gian thực là một bộ các tăng cường cho ngôn ngữ Java, cung cấp cho các

ứng dụng một mức hiệu năng thời gian thực, vượt trội hiệu năng của công nghệ

Java chuẩn. Hiệu năng thời gian thực khác với hiệu năng thông lượng truyền

thống, là một thước đo điển hình của tổng số các chỉ thị, tác vụ, hoặc công việc có

thể được thực hiện trong khoảng thời gian ấn định. Hiệu năng thời gian thực tập

trung vào thời gian mà một ứng dụng yêu cầu để đáp ứng các kích thích bên ngoài

mà không vượt quá các ràng buộc thời gian cho trước. Trong trường hợp của các

hệ thống thời gian thực cứng(hard real-time), các ràng buộc như vậy không bao

giờ được vượt quá; các hệ thống thời gian thực mềm(soft real-time) có một dung

saicao hơn đối với các vi phạm. Hiệu năng thời gian thực đòi hỏi chính ứng dụng

phải giành được quyền điều khiển của bộ xử lý sao cho nó có thể trả lời các kích

thích, và trong khi trả lời các tác nhân kích thích đó thì bộ mã của ứng dụng không

bị khóa do thực hiện các quy trình tương tranh trong máy ảo đó. Java thời gian

thực đưa ra độ đáp ứng mà trước đây chưa được thoả mãn trong các ứng dụng

Java.

pdf36 trang | Chuyên mục: Java | Chia sẻ: dkS00TYs | Lượt xem: 1820 | Lượt tải: 0download
Tóm tắt nội dung Phát triển với Java thời gian thực - Phần 1: Khai thác các đặc tính độc nhất, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
ption e) { 
 } finally { 
 isConsuming = false; 
 } 
 } 
} 
Trong Liệt kê 5, các đối tượng tác nhân tạo ra và tác nhân tiêu thụ truy cập đến 
một hàng đợi của các sự kiện mà được mã hóa như một chuỗi các đối tượng 
java.lang.Integer. Bộ mã này chờ đợi ngữ cảnh cấp phát hiện tại trở thành một 
vùng nhớ được khoanh vùng và chờ các hàng đợi của các sự kiện để được lưu giữ 
như là đối tượng cổng Web (portal object) của vùng đó. (Cổng Web là một đối 
tượng được phân bổ từ vùng mà có thể được lưu giữ trong chính đối tượng vùng 
nhớ được khoanh vùng, một sự tiện lợi hữu ích vì các đối tượng được khoanh 
vùng không thể được lưu trong các trường tĩnh hoặc trong các đối tượng được 
phân bổ từ một vùng cha.) Nếu không tìm thấy hàng đợi, nó sẽ được tạo ra. Một 
cặp trường cấp phát nhanh được dùng để thông báo cho các xử lí quan tâm về tiến 
độ sản xuất và tiêu thụ các sự kiện. 
Hai lớp trong Liệt kê 6 trình bày cách mã trong Liệt kê 5 có thể được thực thi: 
Liệt kê 6. Các lớp có thể lập lịch 
class NoHeapHandler extends AsyncEventHandler { 
 final MemoryArea sharedArea; 
 final Producer producer; 
 NoHeapHandler( 
 PriorityScheduler scheduler, 
 ScopedMemory sharedArea, 
 Producer producer) { 
 super(new PriorityParameters(scheduler.getMaxPriority()), 
 null, null, null, null, true); 
 this.sharedArea = sharedArea; 
 this.producer = producer; 
 } 
 public void handleAsyncEvent() { 
 sharedArea.enter(producer); 
 } 
} 
class NoHeapThread extends NoHeapRealtimeThread { 
 boolean terminate; 
 final MemoryArea sharedArea; 
 final Consumer consumer; 
 NoHeapThread( 
 PriorityScheduler scheduler, 
 ScopedMemory sharedArea, 
 Consumer consumer) { 
 super(new PriorityParameters(scheduler.getNormPriority()), 
 RealtimeThread.getCurrentMemoryArea()); 
 this.sharedArea = sharedArea; 
 this.consumer = consumer; 
 } 
 public synchronized void run() { 
 try { 
 while(true) { 
 if(consumer.setConsuming) { 
 sharedArea.enter(consumer); 
 } else { 
 synchronized(this) { 
 if(!terminate) { 
 if(!consumer.setConsuming) { 
 wait(); 
 } 
 } else { 
 break; 
 } 
 } 
 } 
 } 
 } catch(InterruptedException e) {} 
 } 
} 
Trong Liệt kê 6, bộ mã tác nhân tạo dữ liệu (data-producer) được chỉ định làm một 
bộ xử lý sự kiện không đồng bộ, sẽ được chạy ở quyền ưu tiên cao nhất đang có. 
Bộ xử lý này chỉ cần nhập vào một vùng nhớ được khoanh vùng để chạy bộ mã tác 
nhân tạo ra. Cũng vùng nhớ được khoanh vùng như vậy là một tham số cho một 
lớp NHRT mà hoạt động như tác nhân tiêu thụ của dữ liệu. Lớp xử lí cũng như 
vậy, cho phép truy cập đồng bộ đến các trường terminate và setConsuming cho 
hành vi ra lệnh. Khi xử lí tác nhân tiêu thụ đang tiêu thụ các sự kiện, nó nhập vào 
vùng nhớ được chia sẻ để thực thi mã tác nhân tiêu thụ, chạy với quyền ưu tiên 
thấp hơn tác nhân tạo ra. (Hành vi tiêu thụ trong thí dụ này là không quan trọng, 
chỉ đơn giản là in bộ định danh sự kiện ra bàn điều khiển giao diện.) 
Liệt kê 7 trình bày việc bộ mã khởi tạo hệ thống và thể hiện hành vi hệ thống: 
Liệt kê 7. Hành vi hệ thống 
public class EventSystem implements Runnable { 
 public static void main(String args[]) throws InterruptedException { 
 RealtimeThread systemThread = new RealtimeThread( 
 null, null, null, new VTMemory(20000L), null, null) { 
 public void run() { 
 VTMemory systemArea = new VTMemory(20000L, new 
EventSystem()); 
 systemArea.enter(); 
 } 
 }; 
 systemThread.start(); 
 } 
 public void run() { 
 try { 
 PriorityScheduler scheduler = 
 (PriorityScheduler) Scheduler.getDefaultScheduler(); 
 VTMemory scopedArea = new VTMemory(20000L); 
 Consumer consumer = new Consumer(); 
 NoHeapThread thread = new NoHeapThread(scheduler, scopedArea, 
consumer); 
 Producer producer = new Producer(thread); 
 NoHeapHandler handler = new NoHeapHandler(scheduler, scopedArea, 
producer); 
 AsyncEvent event = new AsyncEvent(); 
 event.addHandler(handler); 
 int handlerPriority = 
 ((PriorityParameters) handler.getSchedulingParameters()).getPriority(); 
 RealtimeThread.currentRealtimeThread().setPriority(handlerPriority - 1); 
 thread.start(); 
 waitForConsumer(consumer); 
 //fire several events while there is a consumer 
 event.fire(); 
 event.fire(); 
 event.fire(); 
 waitForEvent(producer, 3); 
 setConsuming(thread, false); 
 //fire a couple of events while there is no consumer 
 event.fire(); 
 event.fire(); 
 waitForEvent(producer, 5); 
 setConsuming(thread, true); 
 waitForConsumer(consumer); 
 //fire another event while there is a consumer 
 event.fire(); 
 waitForEvent(producer, 6); 
 synchronized(thread) { 
 thread.terminate = true; 
 setConsuming(thread, false); 
 } 
 } catch(InterruptedException e) {} 
 } 
 private void setConsuming(NoHeapThread thread, boolean enabled) { 
 synchronized(thread) { 
 thread.consumer.setConsuming = enabled; 
 thread.notify(); 
 } 
 } 
 private void waitForEvent(Producer producer, int eventNumber) 
 throws InterruptedException { 
 while(producer.eventIdentifier < eventNumber) { 
 Thread.sleep(100); 
 } 
 } 
 private void waitForConsumer(Consumer consumer) 
 throws InterruptedException { 
 while(!consumer.isConsuming) { 
 Thread.sleep(100); 
 } 
 } 
} 
Trong Liệt kê 7, một cặp vùng được sử dụng làm cơ sở cho ngăn xếp vùng đối với 
xử lí và bộ xử lý không-đống, một yêu cầu vì các lớp Schedulable này không thể 
truy cập bất kỳ đối tượng nào mà được phân bổ đống (heap-allocated). Một đối 
tượng sự kiện không đồng bộ đại diện cho sự kiện, với bộ xử lý kèm theo để được 
gửi đi khi sự kiện được thải bỏ. Khi hệ thống được khởi tạo, mã này khởi động xử 
lí tác nhân tiêu thụ và thải bỏ sự kiện vài lần, chạy với quyền ưu tiên chỉ thấp hơn 
quyền ưu tiên của bộ xử lý sự kiện. Bộ mã cũng tắt và bật xử lí tác nhân tiêu thụ 
trong khi bổ sung các sự kiện bị thải bỏ. 
Liệt kê 8 hiển thị đầu ra khi EventSystem (Hệ thống Sự kiện) chạy trong một JVM 
thời gian thực: 
Liệt kê 8. Xuất qua bàn điều khiển 
 1 2 3 6 
Một khía cạnh thú vị của thí dụ này là lý do các sự kiện 4 và 5 không được báo 
cáo. Mỗi khi xử lí nghe (listening thread) báo cáo về các sự kiện trong hàng đợi, 
nó khởi động từ phía trước hàng đợi và đi đến phần cuối, đề nghị rằng tất cả 6 sự 
kiện sẽ được báo cáo ít nhất là một lần. 
Tuy nhiên, thiết kế này đảm bảo rằng bộ nhớ được sử dụng để lưu các sự kiện 
được tự động loại bỏ khi không có xử lí nào tiêu thụ chúng. Khi một xử lí tác nhân 
tiêu thụ ngừng việc đọc từ hàng đợi, nó thoát ra vùng nhớ được khoanh vùng, vào 
lúc mà không có đối tượng Schedulable nào sử dụng vùng này làm ngữ cảnh cấp 
phát. 
Sự vắng mặt của các đối tượng Schedulable bằng cách sử dụng vùng này có nghĩa 
là vùng được khoanh vùng không còn đối tượng nào và được cài đặt lại. Việc này 
gồm cả đối tượng cổng Web, cho nên hàng đợi và tất cả các sự kiện trong nó được 
loại bỏ khi xử lí ngừng việc nghe. Mỗi khi một sự kiện tiếp sau bị thải bỏ, hàng 
đợi sẽ được tạo lại và được đưa dữ liệu vào lại, nhưng không có xử lí nghe, bộ nhớ 
được loại bỏ ngay lập tức sau đó. 
Việc quản lý bộ nhớ là tự động và chạy không bị bộ gom rác can thiệp, nếu bộ 
gom này là đang hoạt động (vì cả bộ xử lý và xử lí đều là không-đống.) Các sự 
kiện được lưu lại làm một hàng đợi của các đối tượng trong bộ nhớ, tiếp tục phát 
triển nếu một xử lí nghe sẵn có để tiêu thụ chúng. Nếu không sẵn có, hàng đợi và 
các sự kiện liên quan tự động được loại bỏ. 
Một kịch bản sử dụng tổng quát 
Với việc lập lịch và khung làm việc quản lý bộ nhớ, bạn có thể thiết kế ra một ứng 
dụng với các mức ưu tiên khác nhau cho các xử lí để thực hiện một cách tối ưu 
trong một máy ảo thời gian thực (và có đầy đủ khả năng trong các máy ảo khác). 
Ứng dụng có thể bao gồm các xử lí quản lí-sự kiện của mức ưu tiên cao, thu thập 
dữ liệu từ các đầu vào bên ngoài và lưu lại dữ liệu để xử lý. Do tính nhất thời và 
không đồng bộ của chúng, các xử lí quản lí-sự kiện này có lẽ thích hợp đối với 
việc quản lý bộ nhớ xen kẽ, và chúng có lẽ phụ thuộc nặng nhất vào các ràng buộc 
thời gian thực. Ở mức ưu tiên trung bình hẳn đang xử lý các xử lí mà tiêu thụ dữ 
liệu và tạo ra các tính toán, hoặc phân phối dữ liệu. Các xử lí mức trung bình có 
thể đòi hỏi áp dụng bộ xử lý trung tâm được phân bổ đầy đủ để quản lý các tải làm 
việc của chúng. Ở các mức ưu tiên thấp nhất, có thể có các xử lí duy trì và ghi nhật 
ký. Việc sử dụng một máy ảo thời gian thực để quản lý lập lịch và sử dụng bộ nhớ 
của các tác vụ khác nhau này trong ứng dụng có thể cho phép nó chạy hiệu quả 
nhất. 
Dự định của RTSJ là cho phép các nhà phát triển viết ra các ứng dụng chạy trong 
các ràng buộc thời gian thực được yêu cầu. Chỉ cần sử dụng bộ lập lịch và các xử 
lí thời gian thực là có thể đủ thực hiện được mục tiêu đó. Nếu không, sự phát triển 
hiện đại hơn có thể là cần thiết để tận dụng một hoặc nhiều đặc tính hiện đại hơn 
do máy ảo thực hiện. 
Kết luận Phần 1 
Bài viết này đã phác thảo ra một số mẹo để bạn bắt đầu hoà nhập các phần tử của 
Java thời gian thực vào ứng dụng Java của bạn. Nó bao hàm một số đặc điểm lập 
lịch và quản lý bộ nhớ mà bạn hẳn muốn sử dụng để thực hiện hiệu năng thời gian 
thực. Đây là một điểm xuất phát để bạn tận dụng các lợi ích truyền thống của ngôn 
ngữ Java, chẳng hạn như sự tương tác và an toàn, và kết hợp chúng với các đặc 
tính mới cho phép bạn thoả mãn các ràng buộc thời gian thực mà ứng dụng của 
bạn đòi hỏi. 
Trong phần tiếp theo ở loạt bài này, bạn sẽ tìm hiểu các kỹ thuật để chuyển một 
ứng dụng hiện hành sang Java thời gian thực. Bài cuối sẽ xây dựng trên hai phần 
đầu và dẫn bạn qua việc thiết kế, xác thực, và gỡ lỗi một hệ thống thời gian thực 
mà hợp nhất với Java thời gian thực. 
 Mục lục 
 Các quy trình con phải bị ràng buộc 
 Các xử lí thời gian thực 
 Các vùng nhớ tách biệt 
 Các tuỳ chọn để lập lịch mã nhạy thời gian 
 Một thí dụ tổng hợp 
 Một kịch bản sử dụng tổng quát 
 Kết luận Phần 1 

File đính kèm:

  • pdfPhát triển với Java thời gian thực, Phần 1 Khai thác các đặc tính độc nhất .pdf
Tài liệu liên quan