使用AsynchronousSocketChannel,ByteBuffer和Future的异常

时间:2015-10-23 10:54:16

标签: java multithreading exception asynchronous

有一项任务:使用 AsynchronousSocketChannel 进行多线程执行功能。为了模拟服务器端的长时间工作,我使用 Thread.sleep()(存储在类Worker中)。如果我的线程超过2秒,当使用 ByteBuffer 未来在客户端使用数据时,苍蝇 java.lang.IndexOutOfBoundsException < / strong>(我的函数 printFuncResult )请告诉我,我的问题是什么?服务器:

public class Server {
public static final InetSocketAddress hostAddress = new InetSocketAddress("localhost", 5678);

private AsynchronousServerSocketChannel serverChannel;
private AsynchronousSocketChannel clientChannel;
ExecutorService threadPool;

public Server() throws IOException, ExecutionException, InterruptedException {
    serverChannel = AsynchronousServerSocketChannel.open();
    serverChannel.bind(hostAddress);
    System.out.println("Server channel bound to port: " + hostAddress.getPort());
    System.out.println("Waiting for client to connect... ");
    getClientChannel();
    handleArguments();
}

private void getClientChannel() throws ExecutionException, InterruptedException {
    Future<AsynchronousSocketChannel> acceptResult = serverChannel.accept();
    clientChannel = acceptResult.get();
}

private void handleArguments() throws IOException, InterruptedException {
    if ((clientChannel != null) && (clientChannel.isOpen())) {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        Future<Integer> result = clientChannel.read(buffer);
        while (! result.isDone()) {
          //  System.out.println("Result coming... ");
        }
        buffer.flip();
        int x = buffer.getInt(0);

        Worker workerOne = new Worker(Worker.TYPE_F, x, clientChannel);
        Worker workerTwo = new Worker(Worker.TYPE_G, x, clientChannel);

        threadPool = Executors.newFixedThreadPool(2);
        threadPool.execute(workerOne);
        threadPool.execute(workerTwo);


        Thread.sleep(3000);
        clientChannel.close();
    }
}
}

class Worker implements Runnable {
public static final int TYPE_F = 1;
public static final int TYPE_G = 2;
private int x;
private int type;
private AsynchronousSocketChannel clientChannel;

public Worker(int type, int x, AsynchronousSocketChannel clientChannel) {
    this.x = x;
    this.type = type;
    this.clientChannel = clientChannel;
}

private void sendResultToClient(int res) {
    ByteBuffer buffer = ByteBuffer.allocate(32);
    if (type == TYPE_F) {
        res = 4545;
    } else {
        res = 34234;
    }
    buffer.putInt(0, type);
    buffer.putInt(4, res);
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for (int i = 0; i < 10000; ++i) {
        for (int j = 0; j < 10000; ++j) {
            int k = i*j + i/(j +1) + i + j + Math.max(i, j);
        }
    }
    boolean written = false;
    while (!written) {
        try {
            clientChannel.write(buffer);
            written = true;
        } catch (Exception e) {}
    }
}

@Override
public void run() {
    int result = -1;
    Random random = new Random();
    switch (type) {
        case TYPE_F :
            result = (int)Math.pow(x, x);
            break;
        case TYPE_G :
            result = (int)Math.pow(x, x / 2);
            break;
    }
    sendResultToClient(result);
}
}

客户端:

public class Client {
private AsynchronousSocketChannel clientChannel;
ExecutorService threadPool;

public Client(int x) throws IOException, InterruptedException, ExecutionException {
    threadPool = Executors.newFixedThreadPool(2);
    boolean connected = false;
    while (!connected) {
        try {
            clientChannel = AsynchronousSocketChannel.open();
            Future<Void> future = clientChannel.connect(Server.hostAddress);
            future.get();
            connected = true;
        } catch (ExecutionException e) {}
    }
    System.out.println("Client is started: " + clientChannel.isOpen());
    System.out.println("Sending messages to server: ");
    sendArguments(x);
    //showCancelDialog();
    listenResult();
    clientChannel.close();
}



private void sendArguments(int x) throws InterruptedException, IOException {
    ByteBuffer buffer = ByteBuffer.allocate(32);
    buffer.putInt(0, x);
    Future<Integer> result = clientChannel.write(buffer);
    while (! result.isDone()) {
        System.out.println("... ");
    }
}

private boolean waitForResult(Future <Pair <Integer, Integer>> futureResult) {
    Scanner sc = new Scanner(System.in);
    while (!futureResult.isDone() ) {
        System.out.println("DOING.. break? (y/n)");
        String input = sc.next();
        if (input.equals("y")) {
            System.out.println("CANCELLED");
            threadPool.shutdownNow();
            return false;
        }
    }
    return true;
}

private void printFuncResult(Future <Pair <Integer, Integer>> futureResult) throws ExecutionException, InterruptedException {
    Integer funcType = new Integer(futureResult.get().getKey());
    Integer result = new Integer(futureResult.get().getValue());

    System.out.println("RESULT OF "+ funcType +" FUNC = " + result);
}

private void listenResult() throws ExecutionException, InterruptedException {

    System.out.println("Wating for result...");

    Listener listener = new Listener(clientChannel);

    Future <Pair <Integer, Integer>> futureResult = threadPool.submit(listener);
    if (!waitForResult(futureResult)) {
        return;
    }

    printFuncResult(futureResult);

    futureResult = threadPool.submit(listener);

    if (!waitForResult(futureResult)) {
        return;
    }

    printFuncResult(futureResult);

}
}

class Listener implements Callable <Pair <Integer, Integer>> {
private AsynchronousSocketChannel clientChannel;

public Listener(AsynchronousSocketChannel channel) {
    this.clientChannel = channel;
}

@Override
public Pair <Integer, Integer> call() throws Exception {
    ByteBuffer buffer = ByteBuffer.allocate(32);
    Future<Integer> futureResult = clientChannel.read(buffer);
    while (! futureResult.isDone()) {}
    buffer.flip();
    Integer type = new Integer(buffer.getInt(0));
    Integer result = new Integer (buffer.getInt(4));
    return new Pair<Integer, Integer>(type, result);
}
}
}

1 个答案:

答案 0 :(得分:0)

IndexOutOfBoundsException不是来自printFuncResult。它仅存储在将来并在那里打印堆栈跟踪。 IndexOutOfBoundsException在此行的Listener调用函数中生成:

Integer type = new Integer(buffer.getInt(0));

如果读取没有读取足够数量的字节,则会发生这种情况。

我建议你替换这种低效且难以调试的循环。

while (! futureResult.isDone()) {}

类似

int bytes_read = futureResult.get();
if(bytes_read != 32) {
   // log error or throw exception or retry ...
}