2012-02-21 7 views
7

Để tạo một câu chuyện dài ngắn, tôi gặp khó khăn khi nhận một vài chuỗi không phải daemon của RMI của Java để đóng sau khi ứng dụng của tôi không còn cần RMI nữa. Điều này ngăn không cho JVM thoát khi main() hoàn thành.RMI Chủ đề ngăn JVM thoát ra sau khi main() hoàn thành

Tôi hiểu rằng việc xuất UnicastRemoteObject s sẽ khiến RMI rời khỏi chuỗi mở cho đến khi bạn gọi thành công UnicastRemoteObject.unexportObject(Object o,boolean force). Dưới đây là một ví dụ (chạy mà không sửa đổi và JVM sẽ thoát bình thường - loại bỏ các cuộc gọi đến unexportObject và JVM sẽ không bao giờ thoát):

import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 
import java.rmi.server.UnicastRemoteObject; 

public class TestUnicastRemoteObject{ 
private static UnicastRemoteObject obj; 
private static Registry registry; 

public static void main(String[] args) throws Exception{ 
    obj = new UnicastRemoteObject(){ 
     private static final long serialVersionUID = 1L; 
    }; 
    System.err.println("created UnicastRemoteObject"); 
    System.err.println("creating registry ..."); 
    registry = LocateRegistry.createRegistry(9999); 
    System.err.println("registry created."); 
    System.err.println("binding obj to registry ..."); 
    registry.bind("Test", obj); 
    System.err.println("bound"); 
    UnicastRemoteObject.unexportObject(obj, true); 
    System.err.println("unexported obj"); 
} 
} 

Ngoài ra, nó dường như không quan trọng cho dù bạn tạo registry và/hoặc gắn kết đối tượng từ xa với nó - điều duy nhất có vẻ quan trọng trong ví dụ này là bất cứ khi nào bạn tạo một UnicastRemoteObject, bạn cần gọi unexportObject để ngăn chặn bất kỳ luồng nào còn lại sau khi bạn hoàn thành. Trong ứng dụng của tôi, tôi đã chắc chắn rằng tôi đã gọi unexportObject trên mỗi UnicastRemoteObject tôi tạo ra, nhưng chuỗi RMI "reaper" và "connection accept" vẫn tồn tại, ngăn không cho JVM của tôi thoát khi ứng dụng của tôi kết thúc bằng tài nguyên RMI.

Có điều gì khác có thể khiến RMI rời khỏi chủ đề phía sau, ngoài việc quên để unexport UnicastRemoteObjects không?

+0

Chương trình thử nghiệm đó có được treo không? Bạn đang sử dụng JRE nào? Bạn đã thử> = 1,6 chưa? Có phải "reaper" và "connection-accept" thực sự là các chủ đề không phải daemon duy nhất còn lại không? – Gray

+0

Có - hai chủ đề này là những chủ đề duy nhất còn lại khi tôi hồ sơ ứng dụng. Chương trình thử nghiệm được cho là tiếp tục chạy sau khi hoàn thành chính, khi bạn nhận xét cuộc gọi đến 'UnicastRemoteObject.unexportObject (obj, true)'. Hành vi mong muốn là dành cho chương trình thử nghiệm để thoát. Tôi nghi ngờ tôi có thể thiếu một cuộc gọi đến unexportObject một nơi nào đó, nhưng chỉ tò mò nếu có bất kỳ cách nào khác để lại RMI chủ đề chạy. – CodeBlind

+0

Và có, tôi đang chạy cả Java 1.6 và 1.7 - hành vi này giống nhau trong cả hai phiên bản. – CodeBlind

Trả lời

7

Chắc chắn, tôi đã gặp lỗi trong mã khiến một trong nhiều (các) UnicastRemoteObject của tôi không tự unexport khi ứng dụng gọi được thực hiện bằng cách sử dụng nó. Vì vậy, câu trả lời là:

Bỏ qua tất cả các UnicastRemoteObject trong một JVM đang chạy là đủ để đóng tất cả các chuỗi không phải daemon.

7

Có vẻ như bạn đã giải quyết được vấn đề của bạn @ Nhưng với hậu thế, tôi nghĩ tôi muốn quảng bá nhận xét của mình cho câu trả lời. Bất cứ khi nào tôi có một loại đăng ký/unregister của mô hình tôi chắc chắn để quản lý chúng thông qua một đối tượng singleton. Bằng cách này bạn có một nơi để đi tìm ra đối tượng nào không được đăng ký. Phơi bày điều này trong JMX cũng là một chiến thắng.

Nội dung nào đó giống như mã sau sẽ tốt. Nó sẽ cho phép bạn đăng nhập hoặc truy vấn JMX để xem những đối tượng nào đã bị ràng buộc vào sổ đăng ký nhưng vẫn chưa được gắn kết.

public class UnicastRegistry { 
    private static Registry registry; 
    private static UnicastRegistry singleton; 
    // private to force the singleton 
    private UnicastRegistry() throws RemoteException { 
     registry = LocateRegistry.createRegistry(9977); 
    } 
    public static UnicastRegistry createSingleton() throws RemoteException { 
     if (singleton == null) { 
      singleton = new UnicastRegistry(); 
     } 
     return singleton; 
    } 
    public void register(String label, Remote obj) throws Exception { 
     registry.bind(label, obj); 
    } 
    public void unregister(String label) throws Exception { 
     Remote remote = registry.lookup(label); 
     registry.unbind(label); 
     if (remote instanceof UnicastRemoteObject) { 
      UnicastRemoteObject.unexportObject(remote, true); 
     } 
    } 
    public void unregisterAll() throws Exception { 
     for (String label : registry.list()) { 
      unregister(label); 
     } 
    } 
    public void printStillBound() throws Exception { 
     String[] stillBound = registry.list(); 
     if (stillBound.length > 0) { 
      System.out.println("Still bound = " + Arrays.toString(stillBound)); 
     } 
    } 
} 
+0

Bạn không cần Bản đồ địa phương. Registry đã là một bản đồ. Bạn có thể thực hiện toàn bộ lớp này mà không có 'registeredMap'. – EJP

+0

Bạn đang thiếu điểm @EJP. Bản đồ hiển thị những gì mọi thứ đã được đăng ký bởi ứng dụng nhưng không được đăng ký. – Gray

+0

Ồ, tôi hiểu rồi. Có một phương thức 'list []'. Tôi sẽ phải xem nếu nó cũng hiển thị các đối tượng bên trong. Tôi sẽ chỉnh sửa câu trả lời của mình. – Gray