马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
从 JDK7 开始,引入了表示异步通道的 AsynchronousSockerChannel 类和 AsynchronousServerSocketChannel 类,这两个类的作用与 SocketChannel 类和 ServerSockelChannel 相似,区别在于异步通道的一些方法总是采用非阻塞模式,并且它们的非阻塞方法会立即返回一个 Future 对象,用来存放方法的异步运算结果
AsynchronousSocketChannel 类有以下非阻塞方法:- // 连接远程主机
- Future<Void> connect(SocketAddress remote);
- // 从通道中读入数据,存放到ByteBuffer中
- // Future对象包含了实际从通道中读到的字节数
- Future<Inleger> read(ByteBuffer dst);
- // 把ByteBuffer的数据写入通道
- // Future对象包含了实际写入通道的字节数
- Future<Integer> write(ByteBuffer src);
复制代码 AsynchronousServerSocketChannel 类有以下非阻塞方法:- // 接受客户连接请求
- // Future对象包含连接建立成功后创建的AsynchronousSockelChannel对象
- Future<AsynchronousSocketChannel> accept();
复制代码 使用异步通道,可以使程序并行执行多个异步操作,例如:- SocketAddress socketAddress = ...;
- AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
- //请求建立连接
- Future<Void> connected = client.connect(socketAddress);
- ByteBuffer byteBuffer = ByteBuffer.allocate(128);
- //执行其他操作
- //...
- //等待连接完成
- connected.get();
- //读取数据
- Future<Integer> future = client.read(byteBuffer);
- //执行其他操作
- //...
- //等待从通道读取数据完成
- future.get();
- byteBuffer.flip();
- WritableByteChannel out = Channels.newChannel(System.out);
- out.write(byteBuffer);
复制代码 下例的代码演示了异步通道的用法,它不断接收用户输入的域名并尝试建立连接,最后打印建立连接所花费的时间。如果程序无法连接到指定的主机,就打印相关错误信息。如果用户输入 bye,就结束程序- //表示连接一个主机的结果
- class PingResult {
-
- InetSocketAddress address;
- long connectStart; //开始连接时的时间
- long connectFinish = 0; //连接成功时的时间
- String failure;
- Future<Void> connectResult; //连接操作的异步运算结果
- AsynchronousSocketChannel socketChannel;
- String host;
- final String ERROR = "连接失败";
-
- PingResult(String host) {
- try {
- this.host = host;
- address = new InetSocketAddress(InetAddress.getByName(host), 80);
- } catch (IOException x) {
- failure = ERROR;
- }
- }
-
- //打印连接一个主机的执行结果
- public void print() {
- String result;
- if (connectFinish != 0) {
- result = Long.toString(connectFinish - connectStart) + "ms";
- } else if (failure != null) {
- result = failure;
- } else {
- result = "Timed out";
- }
- System,out,println("ping "+ host + "的结果" + ":" + result);
- }
-
- public class PingClient {
- //存放所有PingResult结果的队列
- private LinkedList<PingResult> pingResults = new Linkedlist<PingResult>();
- boolean shutdown = false;
- ExecutorService executorService;
-
- public PingClient() throws IOException {
- executorService = Executors.newFixedThreadPool(4);
- executorService.execute(new Printer());
- receivePingAddress();
- }
- }
-
- public static void main(String args[]) throws IOException {
- new PingClient();
- }
-
- /*接收用户输入的主机地址,由线程池执行PingHandler任务 */
- public void receivePingAddress() {
- try {
- BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
- String msg = null;
- //接收用户输入的主机地址
- while((msg = localReader.readLine()) != null) {
- if(msg.equals("bye")) {
- shutdown = true;
- executorService.shutdown();
- break;
- }
- executorService.execute(new PingHandler(msg));
- }
- } catch(IOException e) {}
- }
-
- /* 尝试连接特定主机,生成一个PingResult对象,把它加入PingResults结果队列中 */
- public class PingHandler implements Runnable {
- String msg;
- public PingHandler(String msg) {
- this.msg = msg;
- }
- public void run() {
- if(!msg.equals("bye")) {
- PingResult pingResult = new PingResult(msg);
- AsynchronousSocketChannel socketChannel = null;
- try {
- socketChannel = AsynchronousSocketChannel.open();
- pingResult.connectStart = System.currentTimeMillis();
- synchronized (pingResults) {
- //向pingResults队列加入一个PingResult对象
- pingResults.add(pingResult);
- pingResults,notify();
- }
- Future<Void> connectResult = socketChannel.connect(pingResult.address);
- pingResult.connectResult = connectResult;
- } catch (Exception x) {
- if (socketChannel != null) {
- try { socketChannel.close();} catch (IOException e) {)
- }
- pingResult.failure = pingResult.ERROR;
- }
- }
- }
- }
-
- /* 打印PingResults结果队列中已经执行完毕的任务的结果 */
- public class Printer implements Runnable {
- public void run() {
- PingResult pingResult = null;
- while(!shutdown) {
- synchronized (pingResults) {
- while (!shutdown && pingResults.size() == 0 ) {
- try {
- pingResults.wait(100);
- } catch(InterruptedException e) {
- e.printStackTrace();
- }
- }
- if(shutdown && pingResults.size() == 0 ) break;
- pingResult = pingResults.getFirst();
-
- try {
- if(pingResult.connectResult != null) {
- pingResult.connectResult.get(500, TimeUnit,MILLISECONDS);
- } catch(Exception e) {
- pingResult.failure = pingResult.ERROR;
- }
- }
-
- if(pingResult.connectResult != null && pingResult.connectResult.isDone()) {
- pingResult.connectFinish = System.currentTimeMillis();
- }
-
- if(pingResult,connectResult != null && pingResult.connectResult.isDone() || || pingResult,failure != null) {
- pingResult.print();
- pingResults.removeFirst();
- try {
- pingResult.socketChannel.close();
- } catch (IOException e) {}
- }
- }
- }
- }
- }
- }
复制代码 PingClient 类定义了两个表示特定任务的内部类:
- PingHandler:负责通过异步通道去尝试连接客户端输入的主机地址,并且创建一个 PingResult 对象,它包含了连接操作的异步运算结果,再将其加入 PingResults 结果队列
- Printer:负责打印 PingResults 结果队列已经执行完毕的任务结果,打印完毕的 PingResult 对象会从队列中删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |