JAVA RMI线程模型及内部实现机制

JAVA RMI线程模型及内部实现机制
2010年06月07日
  JAVA RMI是JAVA分布式结构的基础。远程对象的通信过程中,RMI使用标准机制:stub和skeleton。远程对象的stub担当远程对象的客户本地代表或代理人角色,调用程序将调用本地stub的方法,而本地stub将负责执行对远程对象的方法调用。在RMI中,远程对象的stub与该远程对象所实现的远程接口集相同。调用stub的方法时将执行下列操作:
  (1) 初始化与包含远程对象的远程虚拟机的连接;
  (2) 对远程虚拟机的参数进行编组-传输参数;
  (3) 等待远程方法调用结果;
  (4) 解编(读取)返回值或返回的异常;
  (5) 将值返回给调用程序。
  为了向调用程序展示比较简单的调用机制,stub将参数的序列化和网络级通信等细节隐藏了起来。在远程虚拟机中,每个远程对象都可以有相应的skeleton。skeleton负责将调用分配给实际的远程对象实现。它在接收方法调用时执行下列操作:
  (1) 解编(读取)远程方法的参数;
  (2) 调用实际远程对象实现上的方法;
  (3) 将结果(返回值或异常)编组(写入并传输)给调用程序。
  stub和skeleton由rmic编译器生成。在最新的JDK中,不需要手工生产stub和skeleton,用动态代理生成的Proxy代替了stub,而skeleton则取消了。
  我们可以查看源代码来了解RMI的内部实现。Server端调用UnicastRemoteObject的export方法输出远程对象,export方法会在一个线程里监听某个TCP端口上的方法调用请求: public void exportObject(Target target) throws RemoteException { // other code while (true) { ServerSocket myServer = server; if (myServer == null) return; Throwable acceptFailure = null; final Socket socket; try { socket = myServer.accept(); /* * Find client host name (or "0.0.0.0" if unknown) */ InetAddress clientAddr = socket.getInetAddress(); String clientHost = (clientAddr != null ? clientAddr.getHostAddress() : "0.0.0.0"); /* * Spawn non-system thread to handle the connection */ Thread t = (Thread) java.security.AccessController.doPrivileged ( new NewThreadAction(new ConnectionHandler(socket, clientHost), "TCP Connection(" + ++ threadNum + ")-" + clientHost, true, true)); t.start(); } catch (IOException e) { acceptFailure = e; } catch (RuntimeException e) { acceptFailure = e; } catch (Error e) { acceptFailure = e; } } // other code } 上面的代码已被修改以展示主要的要点,Server端就是在ServerSocket的accept方法上面监听到来的请求,如果有新的方法调用请求到来,Server产生一个单独的线程来处理新接收的请求: public void dispatch(Remote obj, RemoteCall call) throws IOException { // positive operation number in 1.1 stubs; // negative version number in 1.2 stubs and beyond... int num; long op; try { // read remote call header ObjectInput in; try { in = call.getInputStream(); num = in.readInt(); if (num >= 0) { if (skel != null) { oldDispatch(obj, call, num); return; } else { throw new UnmarshalException( "skeleton class not found but required " + "for client version"); } } op = in.readLong(); } catch (Exception readEx) { throw new UnmarshalException("error unmarshalling call header", readEx); } /* * Since only system classes (with null class loaders) will be on * the execution stack during parameter unmarshalling for the 1.2 * stub protocol, tell the MarshalInputStream not to bother trying * to resolve classes using its superclasses's default method of * consulting the first non-null class loader on the stack. */ MarshalInputStream marshalStream = (MarshalInputStream) in; marshalStream.skipDefaultResolveClass(); Method method = (Method) hashToMethod_Map.get(new Long(op)); if (method == null) { throw new UnmarshalException("invalid method hash"); } // if calls are being logged, write out object id and operation logCall(obj, method); // unmarshal parameters Class[] types = method.getParameterTypes(); Object[] params = new Object[types.length]; try { unmarshalCustomCallData(in); for (int i = 0; i 结果写入到输出流中:marshalValue(rtype, result, out)。一个方法调用就执行完成了。
  Client端请求一个远程方法调用时,先建立连接:Connection conn = ref.getChannel().newConnection(),然后发送方法参数: marshalValue(types[i], params[i], out),再发送执行方法请求:call.executeCall(),最后得到方法的执行结果:Object returnValue = unmarshalValue(rtype, in),并关闭接:
  ref.getChannel().free(conn, true)。 public Object invoke(Remote obj, java.lang.reflect.Method method, Object[] params, long opnum) throws Exception { if (clientRefLog.isLoggable(Log.VERBOSE)) { clientRefLog.log(Log.VERBOSE, "method: " + method); } if (clientCallLog.isLoggable(Log.VERBOSE)) { logClientCall(obj, method); } Connection conn = ref.getChannel().newConnection(); RemoteCall call = null; boolean reuse = true; /* If the call connection is "reused" early, remember not to * reuse again. */ boolean alreadyFreed = false; try { if (clientRefLog.isLoggable(Log.VERBOSE)) { clientRefLog.log(Log.VERBOSE, "opnum = " + opnum); } // create call context call = new StreamRemoteCall(conn, ref.getObjID(), -1, opnum); // marshal parameters try { ObjectOutput out = call.getOutputStream(); marshalCustomCallData(out); Class[] types = method.getParameterTypes(); for (int i = 0; i socket, clientHost), "TCP Connection(" + ++ threadNum + ")-" + clientHost, true, true)); 在JDK1.6之后,RMI使用线程池来处理新接收的远程方法调用请求-ThreadPoolExecutor。
  下面是一个简单的RMI程序的执行线程抓图,我们可以更好的了解RMI的线程机制。这个简单的RMI程序是服务端有一个远程方法实现,一个客户端同时请求执行这个远程方法100次。在JDK1.5中执行时生成的线程如下图所示,每个方法调用请求都是在一个单独的线程里执行,即 A Thread per Request。
  
  在JDK1.6中执行时生成的线程如下图所示,这些线程都是在ThreadPoolExecutor线程池中执行的。
  
  在JDK1.6中,RMI提供了可配置的线程池参数属性:
  sun.rmi.transport.tcp.maxConnectionThread - 线程池中的最大线程数量
  sun.rmi.transport.tcp.threadKeepAliveTime - 线程池中空闲的线程存活时间
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java RMI(远程方法调用)是Java语言中的一项技术,可以让分散在不同计算机上的程序之间进行远程通信。Java RMI使用Java的序列化机制来传递消息和参数,并通过Java虚拟机(JVM)来实现对远程对象的调用。对于数据库应用而言,Java RMI可以通过网络将客户端与服务器连接起来,并提供一种基于Java的分布式数据库交互方式。 使用Java RMI来连接数据库,可以使得客户端和服务器端的计算机分别处于不同的地点,甚至可以位于不同的城市、不同的国家或不同的大洲。这种分布式的架构使得客户端在终端上只需要安装少量的软件,并且大部分工作都由服务器端完成。同时,Java RMI提供了良好的安全性和稳定性,可以保证数据的安全性和完整性。 对于Java RMI连接数据库的实现,需要涉及到几个方面的知识点。首先是Java的JDBC技术,通过JDBC可以实现对于数据库的访问操作。其次是Java RMI的远程调用机制,需要实现远程对象(Remote Object)的创建。在客户端和服务器端之间建立连接后,客户端可以通过远程对象来调用服务器端提供的操作,并将数据从客户端传递到服务器端进行处理。 总的来说,Java RMI 数据库架构的实现可以为企业提供便捷的分布式数据库操作服务,提高数据安全性和稳定性,并且可以支持异构系统之间的数据共享和集成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值