我指的是在不使用多线程的情况下进行并发处理具体的情况是,在不使用多线程的情况下,服务器侦听某个端口,在有连接进来的时候会调用某个函数对此连接进行处理,但是由于处理的过程可能会比较长,为了不让后面连接的用户等待,需要此函数能异步返回,而不是阻塞在这个函数。之所以希望不使用多线程,是因为考虑到同时连接的用户数会比较多,如果用多线程的话,线程创建,销毁和切换的开销会太大。虽然可以使用线程池,但是这样只是省去了创建和销毁线程的开销,线程切换的开销还是会存在,而且线程的数目也不好确定。.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(); 

}Handler类中的process函数中调用了Thread.Sleep让程序睡眠一段长时间,如果可以异步返回的话,则多个用户可以并发处理,但是不成功 
请问是否少了什么东西? 
或者有什么别的技术?还是说一定使用多线程技术? 
谢谢!
 

解决方案 »

  1.   

    java.util.concurrent packagepublic class ExecutorCompletionService<V>extends Objectimplements CompletionService<V>A CompletionService that uses a supplied Executor to execute tasks. This class arranges that submitted tasks are, upon completion, placed on a queue accessible using take. The class is lightweight enough to be suitable for transient use when processing groups of tasks. Usage Examples. Suppose you have a set of solvers for a certain problem, each returning a value of some type Result, and would like to run them concurrently, processing the results of each of them that return a non-null value, in some method use(Result r). You could write this as:     void solve(Executor e, Collection<Callable<Result>> solvers)
          throws InterruptedException, ExecutionException {
            CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
            for (Callable<Result> s : solvers)
                ecs.submit(s);
            int n = solvers.size();
            for (int i = 0; i < n; ++i) {
                Result r = ecs.take().get();
                if (r != null) 
                    use(r);
            }
        }
     Suppose instead that you would like to use the first non-null result of the set of tasks, ignoring any that encounter exceptions, and cancelling all other tasks when the first one is ready: 
        void solve(Executor e, Collection<Callable<Result>> solvers) 
          throws InterruptedException {
            CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
            int n = solvers.size();
            List<Future<Result>> futures = new ArrayList<Future<Result>>(n);
            Result result = null;
            try {
                for (Callable<Result> s : solvers)
                    futures.add(ecs.submit(s));
                for (int i = 0; i < n; ++i) {
                    try {
                        Result r = ecs.take().get();
                        if (r != null) {
                            result = r;
                            break;
                        }
                    } catch(ExecutionException ignore) {}
                }
            }
            finally {
                for (Future<Result> f : futures)
                    f.cancel(true);
            }        if (result != null)
                use(result);
        }
    直接从JAVA DOC 上COPY过来的,不好意思。 不过觉得确实挺好的。
      

  2.   

    非阻塞效果肯定是通过多线程来处理的
    只是一个是他已经封装了而已
    JAVA对于需要返回值的线程可以用callable接口来做你自己想一下,在一个线程里怎么可能同时处理2个函数
      

  3.   

    非阻塞效果可不是多线程(为每一个request开一个线程,或开个线程池)实现的。 
    非阻塞的目地就是减少多线程给系统资源带来的压力,如果它是靠多线程实现的意义何在!
    JAVA我不知道是怎么实现的,C 在UNIX下编程可是通过system call实现的,是OS支持的。