发帖    主题    评论    推荐    标签    作者    订阅    查搜    注册   登陆   关注
 
面向对象 设计模式 领域驱动设计 企业架构 框架 开发教程 微服务 大数据 扩展性 并发编程 事件驱动 分布式 SOA

请问Java网络编程如何在不使用多线程的情况下实现异步返回?

         
2007-09-29 17:25
赞助商链接

我指的是在不使用多线程的情况下进行并发处理

具体的情况是,在不使用多线程的情况下,服务器侦听某个端口,在有连接进来的时候会调用某个函数对此连接进行处理,但是由于处理的过程可能会比较长,为了不让后面连接的用户等待,需要此函数能异步返回,而不是阻塞在这个函数。

之所以希望不使用多线程,是因为考虑到同时连接的用户数会比较多,如果用多线程的话,线程创建,销毁和切换的开销会太大。虽然可以使用线程池,但是这样只是省去了创建和销毁线程的开销,线程切换的开销还是会存在,而且线程的数目也不好确定。

.NET中的Socket类有个方法是BeginReceive,这个方法中可以定义一个回调函数,在调用BeginReceive之后,回调函数会被调用,而BeginReceive可以立即返回,因此在不使用多线程的情况下可以实现并发处理。

我要的就是这种效果,请问在Java中怎么实现?

我找了些资料,里面提到用ServerSocketChannel,即NIO可以实现非阻塞,但是我实验了一下,好像不行。

代码如下:

package snake.test.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

class Server {


public static void main(String[] args) {
Reactor re = null;
try {
re = new Reactor(6656);
re.run();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}

class Reactor implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocket;

public int num = 0;
Reactor(int port) throws IOException {
selector = Selector.open();
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
serverSocket.configureBlocking(false);
SelectionKey sk = serverSocket.register(selector,
SelectionKey.OP_ACCEPT);
sk.attach(new Acceptor());
}

public void run() { // normally in a new Thread
try {
while (!Thread.interrupted()) {
selector.select();
Set selected = selector.selectedKeys();
Iterator it = selected.iterator();
while (it.hasNext()) {
dispatch((SelectionKey) (it.next()));
}
selected.clear();
}
} catch (IOException ex) { /* ... */
}
}

void dispatch(SelectionKey k) {
Runnable r = (Runnable) (k.attachment());
if (r != null)
r.run();
}

class Acceptor implements Runnable { // inner
public void run() {
try {
num++;
SocketChannel c = serverSocket.accept();
if (c != null)
new Handler(selector, c, num);
} catch (IOException ex) { /* ... */
}
}
}



}

////////////////////////////////////////////


package snake.test.channel;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

final class Handler implements Runnable {
final SocketChannel socket;
final SelectionKey sk;
ByteBuffer input = ByteBuffer.allocate(1024);
ByteBuffer output = ByteBuffer.allocate(1024);
static final int READING = 0, SENDING = 1;
int state = READING;

private int num = 0;

Handler(Selector sel, SocketChannel c,int n) throws IOException {
System.out.println("Client Startup");
socket = c;
num = n;
c.configureBlocking(false);
// Optionally try first read now
sk = socket.register(sel, 0);
sk.attach(this);
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}

boolean inputIsComplete() {

return true; /* ... */
}

boolean outputIsComplete() {
return true; /* ... */
}

void process() {
//System.out.println("Sleep");
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

// class Handler continued
public void run() {
try {
System.out.println("Run " + num);
if (state == READING)
read();
else if (state == SENDING)
send();
} catch (IOException ex) { /* ... */
}
}

void read() throws IOException {

socket.read(input);
if (inputIsComplete()) {
process();
state = SENDING;
// Normally also do first write now
sk.interestOps(SelectionKey.OP_WRITE);
}
}

void send() throws IOException {
socket.write(output);
if (outputIsComplete())
sk.cancel();
}
}


请问是否少了什么东西?
或者有什么别的技术?还是说一定使用多线程技术?
谢谢!

2007-09-29 17:27

补充一下,Handler类中的process函数中调用了Thread.Sleep让程序睡眠一段长时间,如果可以异步返回的话,则多个用户可以并发处理,但是不成功

麻烦各位帮忙看看谢谢

2007-09-30 15:12

NIO是不阻塞的等待一个连接,而是采用了监听的方式来实现,到后面,你需要read,write的时候,如果所需的条件没有准备好,其实一样要阻塞的啊。
如果不想让用户等待,肯定至少用户调用的方法,和执行昂贵的操作的方法,肯定不能是一个线程了,但是不一定要每次都开一个线程,我们可以重复的利用一个线程来不停执行新的请求所需要的昂贵操作。
这里可以使用生产者消费者模式,你可以顺便研究一下1.5加入的concurrent包,肯定可以满足你的要求

异步编程      nio     

赞助商链接

赞助商链接

返回顶部

移动版 关于本站 使用帮助 联系管理员 最佳分辨率1366x768
OpenSource JIVEJDON Powered by JdonFramework Code © 2002-20 jdon.com