学士后类

使用Exchanger实现两个线程之间的数据交互

在线咨询 来源:北大青鸟

在看Jetty源码中的EndPointTest类,对EndPoint的测试:
1. 建立一个连接(创建ServerSocket实例,一般还会给定一个端口,其实可以bind(null)以让操作系统分配一个可用端口),新启动一个线程,在新线程中监听给定端口(调用accept方法)。
2. 发送客户端请求(创建一个Socket实例,并向该Socket写入请求数据)。
3. 在接收端读取数据,验证写入的请求和接收到的数据相同。

在以上流程实现中,accept方法返回的接收端Socket需要传给主线程,同时要保证使用该Socket是在accept方法返回之后,以我习惯,我会使用一个Lock或CountDownLatch:

private static class SocketHolder {
   Socket socket;
}

@Test
public void levinOldWayTest() throws Exception {
   final ServerSocket server = new ServerSocket(10240);
   
   final CountDownLatch latch = new CountDownLatch(1);
   final SocketHolder socketHolder = new SocketHolder();
   new Thread() {
       public void run() {
           try {
               socketHolder.socket = server.accept();
               latch.countDown();
           } catch(Exception ex) {
               ex.printStackTrace();
           }
       }
   }.start();
   
   Socket socket = new Socket(server.getInetAddress(), server.getLocalPort());
   socket.getOutputStream().write("My Test String".getBytes());
   
   latch.await(5, TimeUnit.SECONDS);
   byte[] receives = new byte[4096];
   int length = socketHolder.socket.getInputStream().read(receives);
   
   assertEquals("My Test String", new String(receives, 0, length));
   
   socket.close();
   socketHolder.socket.close();
   server.close();
}

不知道有多少人也像我一样把这段代码写成这样?这里有两个问题:
1. ServerSocket的监听的端口不一定是可用的,类似测试代码我之前没有写过,我估计自己正真在写的时候应该会想到让操作系统动态分配。
2. 为了在两个线程中传递数据,这里首先创建了一个SocketHolder类,然后使用CountDownLatch,写起来好麻烦。为了简化这段代码,可以使用Exchanger,即当一个生产者线程准备好数据后可以通过Exchanger将数据传递给消费者,而消费者在生产者传递过来数据后就可以消费了,这里的数据就是Socket。

改进后的代码如下:
@Test
public void levinImprovedWayTest() throws Exception {
   final ServerSocket server = new ServerSocket();
   server.bind(null);
   
   final Exchanger<Socket> exchanger = new Exchanger<Socket>();
   new Thread() {
       public void run() {
           try {
               exchanger.exchange(server.accept());
           } catch(Exception ex) {
               ex.printStackTrace();
           }
       }
   }.start();
   
   Socket socket = new Socket(server.getInetAddress(), server.getLocalPort());
   socket.getOutputStream().write("My Test String".getBytes());
   
   Socket receiverSocket = exchanger.exchange(null, 5, TimeUnit.SECONDS);
   byte[] receives = new byte[4096];
   int length = receiverSocket.getInputStream().read(receives);
   
   assertEquals("My Test String", new String(receives, 0, length));
   
   socket.close();
   receiverSocket.close();
   server.close();
}

  • JAVA培训

    班型:

    本期开课:0000-00-00

    在线咨询
  • ACCP软件培训

    班型:全日制班 周末班

    本期开课:2014-12-24

    在线咨询
  • 微软.NET培训

    班型:全日制班 周末班

    本期开课:2014-12-29

    在线咨询
  • BENET培训

    班型:全日制班 周末班

    本期开课:2014-12-21

    在线咨询
  • 网络营销培训

    班型:全日制班 周末班

    本期开课:2014-12-26

    在线咨询