2012-08-16 61 views
0

我必须通过某个端口向一些计算机发送一组文件。事实是,每次调用发送文件的方法时,都会计算目标数据(地址和端口)。因此,使用为每个方法调用创建一个线程的循环,并用BindException的try-catch语句包围方法调用,以处理尝试使用已使用端口的程序的情况(不同的目标地址可能通过相同的端口接收消息)告诉线程等待几秒钟,然后重新启动重试,并继续尝试,直到不会抛出异常(运输成功执行)。 我不知道为什么(虽然我第一次看到它的时候可以猜到),Netbeans警告我说,在循环中睡眠一个Thread对象并不是最好的选择。然后我搜索了一下以获取更多信息,并找到this link to another stackoverflow post, which looked so interesting(我从来没有听说过the ThreadPoolExecutor class)。我一直在阅读这个链接和API以改进我的程序,但我还不确定我应该如何将它应用到我的程序中。请有人帮忙吗?告诉ThreadPoolExecutor何时应该继续运行

编辑:重要的代码:

 for (Iterator<String> it = ConnectionsPanel.list.getSelectedValuesList().iterator(); it.hasNext();) { 
     final String x = it.next(); 
     new Thread() { 

      @Override 
      public void run() { 
       ConnectionsPanel.singleAddVideos(x); 
      } 
     }.start(); 
    } 

    private static void singleAddVideos(String connName) { 
    String newVideosInfo = ""; 

    for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) { 
     newVideosInfo = newVideosInfo.concat(it.next().toString()); 
    } 

    try { 
     MassiveDesktopClient.sendMessage("hi", connName); 
     if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) { 
      MassiveDesktopClient.sendMessage(newVideosInfo, connName); 
     } 
    } catch (BindException ex) { 
     MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber()); 
     try { 
      Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000); 
     } catch (InterruptedException ex1) { 
      JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE); 
     } 
     ConnectionsPanel.singleAddVideos(connName); 
     return; 
    } 

    for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) { 
     try { 
      MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName); 
     } catch (BindException ex) { 
      MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber()); 
      try { 
       Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000); 
      } catch (InterruptedException ex1) { 
       JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE); 
      } 
      ConnectionsPanel.singleAddVideos(connName); 
      return; 
     } 
    } 
} 
+2

而不是谈论它,你应该后t他自己编码。 – 2012-08-16 18:45:42

+0

如果您将用户名改为真实的话,我会为您+1,那么您将拥有21的代表,这应该足以访问stackoverflow聊天(位于评论链接旁边的顶部)。因为你提出的问题不是问题。 – 2012-08-16 19:30:28

+0

我以为名字改变的可能性要求最低的声望,对不起老兄。 @MarkoTopolnik,代码补充说。感谢您的关注(我通过解释会比代码更受欢迎)。 – 2012-08-16 20:11:47

回答

1

你的问题不是很清楚 - 我知道你想重新运行你的任务,直到成功为止(没有的BindException)。要做到这一点,你可以:

  • 尽量不捕捉异常
  • 捕获来自未来
  • 例外重新安排任务稍后运行你的代码,如果它失败

一简化的代码将如下 - 添加错误消息,并根据需要进行优化:

public static void main(String[] args) throws Exception { 
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(corePoolSize); 
    final String x = "video"; 
    Callable<Void> yourTask = new Callable<Void>() { 
     @Override 
     public Void call() throws BindException { 
      ConnectionsPanel.singleAddVideos(x); 
      return null; 
     } 
    }; 
    Future f = scheduler.submit(yourTask); 
    boolean added = false; //it will retry until success 
          //you might use an int instead to retry 
          //n times only and avoid the risk of infinite loop 
    while (!added) { 
     try { 
      f.get(); 
      added = true; //added set to true if no exception caught 
     } catch (ExecutionException e) { 
      if (e.getCause() instanceof BindException) { 
       scheduler.schedule(yourTask, 3, TimeUnit.SECONDS); //reschedule in 3 seconds 
      } else { 
       //another exception was thrown => handle it 
      } 
     } 
    } 
} 

public static class ConnectionsPanel { 

    private static void singleAddVideos(String connName) throws BindException { 
     String newVideosInfo = ""; 

     for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) { 
      newVideosInfo = newVideosInfo.concat(it.next().toString()); 
     } 

     MassiveDesktopClient.sendMessage("hi", connName); 
     if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) { 
      MassiveDesktopClient.sendMessage(newVideosInfo, connName); 
     } 

     for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) { 
      MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName); 
     } 
    } 
} 
+0

感谢您的帮助,但这并没有改善我的做法。在这种情况下,如果BindException抛出,程序所做的是等待并重复(与我的程序一样)。我期望通过这个新的课程来达到目的(抱歉,如果它不是100%清楚,我的错)是这样的:“我是队列中的一个线程,必须使用端口33333,但是当我尝试过使用它我得到了一个BindException,因为另一个人正在使用它,所以让我们等待,直到我收到警告说端口是空闲的,然后我可能会重试(并且一次又一次,直到我得到绑定港口)。” – 2012-08-17 11:01:35

+0

@Stoyicker所以区别在于,不是每隔x秒重试一次,直到它工作,而是希望使用某种监听器/回调函数,让您知道端口何时可以使用并在这种情况发生时运行? – assylias 2012-08-17 11:04:35

+0

是的,因为在那种情况下,我将能够最小化任务必须在队列中的时间,但同时确保没有成功完成任务就不会被抛弃。 – 2012-08-17 11:18:26