Проблемы реализации с ThreadPoolExecutor - PullRequest
1 голос
/ 10 ноября 2011

Я использую несколько потоков для загрузки файлов на сервер. Апплет Java отвечает за отображение пользовательского интерфейса. Сначала я запускаю 5 потоков с помощью ThreadPoolExecutor и назначаю им 5 файлов. После каждой загрузки я получаю уведомление с сервера. Когда поток завершает выполнение, другой новый поток назначается с файлом, пока все файлы не будут загружены на сервер.

Основная структура кода выглядит следующим образом:

i> метод startUpload () вызывается из Java-апплета, который отвечает за обработку функций загрузки.

class Upload extends Runnable{


...............................
..............................

public void startUpload() {

............................... //other initialisations done

    int waitTime = 500;

    Random random = new Random();

    ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300));

    while (it.hasNext()) {

                int time = random.nextInt(1000);
                waitTime += time;
                newFile = new File((String) it.next());

                executor.execute(new Runnable() {

                    @Override
                    public void run() {

                       try{
                       Thread.sleep(wait);
                       }
                       catch(Exception e){
                        }
                        processFile1(newFile);
                    }
                });

            }
           try {
                Thread.sleep(waitTime);
                executor.shutdown();
                executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);

            } catch (Exception e) {
            }

    }

}

Проблема, с которой я сейчас сталкиваюсь.

i> Пользовательский интерфейс обновляется только в конце загрузки всех файлов. На промежуточном этапе пользовательский интерфейс находится в подвешенном состоянии. Похоже, EDT переходит в заблокированное состояние.

Тот же код для рендеринга пользовательского интерфейса работал нормально, когда я использовал класс Thread, notify / sleep для реализации той же функциональности. Я изменил код на ThreadPoolExecutor, поскольку в одном из блогов / статей я не увидел, что это лучший способ реализации многопоточности из Java версии 5.0.

ii> Еще одна вещь, которую я заметил с ThreadPoolExecutor, когда я загружаю несколько файлов размером 1 КБ (для целей тестирования), если я удаляю все wait () из приведенного выше кода, следующая строка назначает новый файл, но один и тот же файл всегда загружается несколькими потоками.

newFile = новый файл ((строка) it.next ());

Но при добавлении sleep () с помощью run () несколько потоков загружают на сервер разные файлы.

Есть ли проблемы с реализацией вышеуказанного кода?

Ответы [ 2 ]

2 голосов
/ 10 ноября 2011

Проблема 1: newFile является (статическим?) Полем вместо локальной переменной.

Вам нужно убедиться, что локальный захват newFile отличается в каждом цикле.Таким образом, он должен выглядеть примерно так:

while(it.hasNext()) {
  final File newFile = new File((String) it.next());
  executor.execute(new Runnable() {
    @Override
    public void run() {
      processFile1(newFile); // Local only to this iteration of the loop.
    }
  }
}

Ваш код полностью обернут в экземпляр Runnable.Можете ли вы дать нам знать, с какой нити это называется?Если он находится на EDT, то это объясняет, почему пользовательский интерфейс блокируется.

Небольшая проблема - отсутствие универсальных элементов в вашем итераторе.Теоретически, вы должны перебирать коллекцию строк:

Collection<String> listOfFiles = ...

Iterator<String> it = listOfFiles.iterator();

while(it.hasNext()) { 
  String filename = it.next(); // No cast necessary
}
1 голос
/ 10 ноября 2011

Пользовательский интерфейс зависает, потому что вы блокируете поток EDT.Этот код является виновником:

   try {
        Thread.sleep(waitTime);
        executor.shutdown();
        executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);

    } catch (Exception e) {
    }

Идея ExecutorService состоит в том, что вы создаете его один раз во время инициализации и никогда не закрываете его, пока программа не будет готова к выходу.Идиома для этого может быть:

ExecutorService executor = Executors.newFixedThreadPool(5);
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        executor.shutdown();
    }
});

Как упоминалось @ Bringer128, вторая проблема вызвана тем, что вы меняете значение статической переменной или переменной-члена и не назначаете ссылку File нановое место.Если бы код был верным, мы бы ожидали увидеть newFile, объявленный как final File newFile, потому что неконечные локальные переменные не могут быть указаны во внутреннем классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...