循环屏障重用?

时间:2013-10-12 00:38:27

标签: java multithreading sockets concurrency cyclicbarrier

我目前正在尝试实现一个与机器通信的应用程序,它应该基本上如下工作:

  • 程序向服务器发送消息(在这种情况下,文件的前255个字节)。
  • 机器响应“消息已成功接收”或“错误 收到消息“回复。
  • 程序然后必须决定是否发送下一条消息(下一个255字节)(最后一条消息的错误,必须重新开始),具体取决于机器的响应。
  • 等等,程序需要发送的每条消息(取决于文件的大小)。

所以,我们想到有一个线程来做发送,另一个做接收,因为我们有一个api来注册一个类来接收来自机器的消息(只是通过实现一个接口),以及向机器发送消息的方法不属于阻塞类型,因此需要等待机器响应的方法,以便程序可以在响应到达后决定做什么。

因此,我们需要以某种方式同步这两个线程,因为它可以确定它们将交换多少消息,这使我们尝试使用CyclicBarrier。这是用于测试CyclicBarrier是否可以帮助我们解决此问题的代码(程序实际上不使用套接字与机器通信,这仅用于测试屏障):

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class BlockingTest{
  private CyclicBarrier barrier;

  class Receiver implements Runnable{
    @Override public void run(){
      try{
        ServerSocket ss = new ServerSocket(8080);
        while(!barrier.isBroken()){
          System.out.println("Waiting message...");
          Socket response = ss.accept();
          BufferedReader br = new BufferedReader(new InputStreamReader(
              response.getInputStream()));
          System.out.printf("Received: %s\n", br.readLine());
          barrier.await();
        }
      }catch(InterruptedException | BrokenBarrierException |
        IOException ex){
        System.err.println(ex.getMessage());
      }
    }
  }

  public BlockingTest(){
    this.barrier = new CyclicBarrier(2, new Runnable(){
      @Override public void run(){
        System.out.println("done.");
      }
    });

    new Thread(new Receiver()).start();

    try{
      Socket sender = new Socket("localhost", 8080);
      PrintWriter pw = new PrintWriter(sender.getOutputStream(), true);
      for(int i = 0; i < 3; i++){
        System.out.println("Sending message:");
        pw.println("Message!");
        this.barrier.await();
      }
    }catch(InterruptedException | BrokenBarrierException | IOException ex){
      System.err.println(ex.getMessage());
    }
  }

  public static void main(String[] arg){
    new BlockingTest();
  }
}

如果我们只发送一条消息(BlockingTest()构造函数中的块没有,只发送消息),此代码按预期工作,但添加for块后,它不能按预期工作。它只在第一次工作,然后挂起:

Waiting message...
Sending message:
Received: Message!
done.
Waiting message...
Sending message:

问题是:

  • 如何使屏障可重复使用?这是自动的还是有的 手工完成?

  • 由于插座(或屏障代码)错过了某些内容,程序是否悬空?

1 个答案:

答案 0 :(得分:0)

它挂起的原因是你打开一个到服务器的连接并继续向它发送数据,但是在接收端,你丢弃了第一个连接,并开始等待下一个连接发生。

每次发送数据时都可以从发件人创建新连接。代码块

Socket sender = new Socket("localhost", 8080);
PrintWriter pw = new PrintWriter(sender.getOutputStream(), true);

必须在for循环中移动。 (当然,注意释放所有资源)

OR,

修复接收方从第一个连接读取数据,而不是等待第二个数据包的新连接。