Синхронизированный метод продолжает вызываться - PullRequest
0 голосов
/ 19 апреля 2011

Я все еще немного новичок в многопоточности, так что, возможно, это простой ответ, но я попытался искать с помощью блокировок и синхронизированных методов, но это не сработало.

У меня есть система, которая подключается к FTP-сайту и загружает XML-файл для обработки. Приложение ожидает обновления файла на сайте ftp, если оно не обновляется, оно ничего не делает. Если он обновляется, он загружает XML-файл, чтобы начать обработку.

Перед обработкой XML мы проверяем версию файла на сервере и версию чего-либо в базе данных, если версии не совпадают, создайте новый поток и обновите файл на сервере до новая версия.

Так что в коде это в значительной степени:

if(file.version.equals(db.version))
{ 
  do work...
}
else 
{
  startUpdateThread();
}

private synchronized void startUpdateThread()
{
   Runnable updateRunnable = new UpdateRunnable();
   Thread updateThread = new Thread(updateRunnable);
   updateThread.start();
}

Проблема, с которой я столкнулся, заключается в том, что xml-файл изменится на ftp-сайте в процессе обновления файла на сервере и все еще будет вводить метод startUpdateThread (), и к тому времени, когда он будет завершен, у меня будет несколько потоков для выполнения тех же задач.

Мой вопрос, который я предполагаю, состоит в том, почему синхронизированный метод все еще вызывается, даже если он должен быть заблокирован, и если я делаю это неправильно, как правильно подойти к этому, не создавая несколько потоков для выполнения одних и тех же задач.

редактировать Небольшое дальнейшее объяснение системы: файл на сервере загружается в кеш при запуске приложения, поэтому файл file.version.equals действительно из кеша. Файл нужно обновлять только раз в несколько месяцев. Это делается вручную, и я собираюсь сделать это автоматически.

Файл на сервере и XML-файл не имеют ничего общего друг с другом, просто случается, что эта проверка запускается, когда приложение видит, что файл на сервере изменился (что происходит примерно каждые две минуты). Создание нового файла и загрузка его в кеш занимает около 10 минут. Таким образом, проверка происходит примерно 5 раз, таким образом, создается 5 потоков и создается файл.

Желаемый результат:

Обычная обработка для продолжения работы с xml-файлом

ОДИН новый поток создается для перезагрузки полностью отдельного файла на сервере.

Надеюсь, это имеет смысл ...

Ответы [ 4 ]

1 голос
/ 19 апреля 2011

Конечно, метод startUpdateThread() синхронизирован, но не фактическое выполнение потоков.Блокировка снимается, когда завершается вызов updateThread.start() - и это происходит задолго до завершения рабочего потока.

Вопрос в том, каково ваше желаемое поведение: если удаленный файл изменяется во время его обработки, тогда онНасколько я понимаю, измененный файл имеет другой номер.

Вы можете отправить сигнал работающему рабочему потоку, чтобы остановить обработку этого файла, поскольку он уже устарел.Или вы хотите, чтобы «второй» рабочий поток дождался завершения первого?В этом случае может помочь ThreadPool с размером 1.

0 голосов
/ 19 апреля 2011

Я немного растерялся в логике того, что вы делаете, но я могу рассказать вам, как работает «синхронизированный», и тогда вы сможете убедиться, что ваша логика следует этому.

Когда вы делаете «Обычный метод экземпляра (такой как этот) синхронизирован, тогда это фактически означает, что только один поток за раз может выполнять любой синхронизированный метод для одного и того же объекта.(Или может быть внутри любого кода, явно синхронизирующегося с рассматриваемым объектом.)

Я не знаю, влияет ли это на то, что вы делаете, но обратите внимание, что у меня может быть класс следующим образом:

public class MyClass {
  public synchronized void someMethod() {
    ...
  }
}

, а затем по-прежнему есть два отдельных экземпляра MyClass, каждый с вызовом someMethod (), выполняющимся одновременно в разных потоках.С другой стороны, на том же экземпляре MyClass , что и у , у меня не может быть двух вызовов одновременно функции someMethod ().

Если вы немного потерялись из-за синхронизации, тогдаВы также можете рассмотреть возможность использования одной из явных блокировок, введенных в Java 5. (Если это поможет, у меня есть несколько статей о Java 5 Locks и даже о синхронизации и параллелизме в целом омой веб-сайт, на который вы, возможно, захотите взглянуть.)

0 голосов
/ 19 апреля 2011

Я предлагаю вам выполнить одну задачу для проверки и одну или несколько задач для обработки / загрузки.

Проблема, с которой вы столкнулись, состоит в том, что многие потоки выполняют проверку одновременно, и все они видятфайл должен быть загружен, поэтому все они вызывают startUpdateThread()

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

Однако, поскольку вы каждый раз запускаете новый поток, мне не совсем понятно, почему вы вообще вызываете этот метод в многопоточном dmanner.Я бы просто использовал один поток для проверки.

Очевидно, что вам не следует проверять файл повторно во время его обновления.;)

Вместо того, чтобы запускать поток каждый раз, я предлагаю вам использовать ExecutorService для объединения ваших потоков.

0 голосов
/ 19 апреля 2011

Я думаю, что вы неправильно понимаете конструкции параллелизма в Java. startUpdateThread() запустит поток обновления и мгновенно вернется, поэтому блокировка бесполезна. Вероятно, вам нужно сохранить updateThread в виде поля и проверить, является ли оно пустым во время блокировки synchronized (this), перед вызовом startUpdateThread.

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