Как сообщить ThreadPoolExecutor, когда он должен работать или нет

Мне нужно отправить набор файлов на несколько компьютеров через определенный порт. Дело в том, что каждый раз, когда вызывается метод, отправляющий файлы, вычисляются данные назначения (адрес и порт). Следовательно, используя цикл, который создает поток для каждого вызова метода и окружает вызов метода оператором try-catch для BindException, чтобы обработать ситуацию, когда программа пытается использовать порт, который уже используется (могут быть разные адреса назначения. получить сообщение через тот же порт), сообщая потоку подождать несколько секунд, а затем перезапустить, чтобы повторить попытку, и продолжайте попытки до тех пор, пока исключение не будет сгенерировано (доставка успешно выполнена). Я не знал, почему (хотя я мог догадаться, когда впервые увидел это), Netbeans предупредил меня о том, что спящий объект Thread внутри цикла - не лучший выбор. Затем я немного погуглил для получения дополнительной информации и нашел эту ссылку на другой Сообщение stackoverflow, которое выглядело так интересно (я никогда не слышал о класс ThreadPoolExecutor). Я читал и эту ссылку, и API, чтобы попытаться улучшить свою программу, но я еще не совсем уверен, как мне применить это в своей программе. Может ли кто-нибудь помочь в этом, пожалуйста?

РЕДАКТИРОВАТЬ: важный код:

        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;
        }
    }
}

person Jorge Antonio Díaz-Benito    schedule 16.08.2012    source источник
comment
Вместо того, чтобы говорить об этом, вы должны опубликовать сам код.   -  person Marko Topolnik    schedule 16.08.2012
comment
Я поставлю +1 вам, если вы измените свое имя пользователя на что-то реальное, тогда у вас будет 21 репутация, которой должно хватить для доступа к чату stackoverflow (вверху рядом со ссылкой на обзор). Потому что вопрос не в том, о чем вы спрашиваете.   -  person Adam Gent    schedule 16.08.2012
comment
Я думал, что возможность смены имени требует минимальной репутации, извини, чувак. @MarkoTopolnik, код добавлен. Спасибо за проявленный интерес (хотя я предпочел бы объяснение, а не код).   -  person Jorge Antonio Díaz-Benito    schedule 17.08.2012
comment
Ваш вопрос все еще очень неясен. Стена текста, за которым очень трудно следить, и фрагмент кода, который очень мало проясняет. Все еще не настоящий вопрос.   -  person Marko Topolnik    schedule 17.08.2012
comment
По сути, моя проблема в том, как указать tpe запускать задачи не в течение определенного времени, а до тех пор, пока они не будут должным образом завершены (что означает, что они не генерируют исключение BindException). Поскольку указание конструктору ограничения по времени для каждого потока, даже если установлено значение Integer.MAX_VALUE, вызовет проблему, поскольку почти всегда будет необходимо отправить материал в два или более разных места назначения через одни и те же порты и, если материал для отправки состоит из множества файлов, каждая доставка может занять больше указанного времени, и поэтому другие отправки через эти порты будут пропущены.   -  person Jorge Antonio Díaz-Benito    schedule 17.08.2012


Ответы (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);
        }
    }
}
person assylias    schedule 17.08.2012
comment
Спасибо за вашу помощь, но это не улучшает мой способ работы. В этом случае, если выбрасывается исключение BindException, программа ожидает и повторяет (то же самое, что и моя программа). То, что я ожидал достичь с этими новыми для меня классами (извините, если это не было на 100% ясным, моя вина), было примерно таким: я - поток в очереди, который должен использовать порт 33333, но когда я Я пытался использовать его. Я получил исключение BindException, потому что его использует другой, так что давайте подождем, пока я не получу предупреждение о том, что порт свободен, а затем я могу повторить попытку (и это снова и снова, пока я не смогу привязать порт ). - person Jorge Antonio Díaz-Benito; 17.08.2012
comment
@Stoyicker Итак, разница в том, что вместо того, чтобы повторять попытки каждые x секунд, пока он не заработает, вы хотите использовать какой-то прослушиватель / обратный вызов, который сообщит вам, когда порт будет готов к использованию и запустится, когда это произойдет? - person assylias; 17.08.2012
comment
Да, потому что в этом случае я смогу минимизировать время, в течение которого задача должна находиться в очереди, но в то же время убедиться, что ни одна задача не будет выброшена из нее без успешного завершения. - person Jorge Antonio Díaz-Benito; 17.08.2012
comment
Вы можете использовать CompletionService - отметьте аналогичный вопрос. - person assylias; 17.08.2012
comment
Приятно знать об этом классе, спасибо. Связанный вопрос и эта ссылка позволили мне решить мою проблему . - person Jorge Antonio Díaz-Benito; 17.08.2012