2012-02-23 3 views
3

У меня есть приложение, которому нужно подождать некоторое неизвестное количество времени. Он должен дождаться, пока несколько полей данных будут заполнены сервером.Лучший способ ожидания в Java

API между сервером и предоставляет мне возможность запрашивать данные, достаточно легко ...

API между сервером и предоставляет возможность получить свои данные обратно, одно поле в то время. Это не говорит мне, когда все поля будут заполнены.

Каков наиболее эффективный способ подождать, пока мой запрос будет обработан сервером? Вот некоторые псевдокод:

public class ServerRequestMethods { 
    public void requestData(); 
} 

public interface ServerDeliveryMethods { 
    public void receiveData(String field, int value); 
} 

public class MyApp extends ServerRequestMethods implements ServerDeliveryMethods { 
    //store data fields and their respective values 
    public Hashtable<String, Integer> myData;  

    //implement required ServerDeliveryMethods 
    public void receiveData(String field, int value) { 
     myData.put(field, value);  
    } 

    public static void main(String[] args) { 
     this.requestData(); 

     // Now I have to wait for all of the fields to be populated, 
     // so that I can decide what to do next. 

     decideWhatToDoNext(); 
     doIt(); 
    } 
} 

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

wait() и notify() с помощью метода, защищающего цикл while, который проверяет, есть ли у меня все необходимые значения, каждый раз, когда я проснулся уведомлением()?

Наблюдатель и наблюдаемый метод, который проверяет, есть ли у меня все необходимые значения при каждом вызове моего Observer.Update()?

Каков наилучший подход? Благодарю.

+0

«API-интерфейс сервера также обеспечивает способ получения моих данных назад, по одному полю за раз». Как это работает? Ожидается ли, что вызов будет заполнен этим конкретным полем или он будет немедленно возвращен, с данными поля или без них? –

+0

@ сорок два Для того, чтобы получать сообщения назад, сервер требует, чтобы я реализовал интерфейс «ServerDeliveryMethods» в psuedocode. Поэтому, когда сервер отправляет мне данные, он вызывает этот метод и заполняет данные в параметрах. – rallison

+0

Вопрос в том, что ваше приложение-клиент считает «выполненным»? Независимо от того, что вам, скорее всего, понадобится отдельный поток для связи с сервером, и семафор (концепция, а не класс), чтобы ждать в вашем основном потоке, который защищает метод 'solveWhatToDoNext(). – Perception

ответ

5

Если я прямо вас понял, некоторые другие нить звонки receiveData на вашем MyApp заполнить данные. Если это так, то вот как вы это делаете:

  1. Спит, как это:

    do { 
        this.wait(someSmallTime); //We are aquiring a monitor on "this" object, so it would require a notification. You should put some time (like 100msec maybe) to prevent very rare but still possible deadlock, when notification came before this.wait was called. 
    } while (!allFieldsAreFilled()); 
    
  2. receiveData должен сделать notify вызова, unpause что wait вызова вашего. Например, как это:

    myData.put(field, value); 
    this.notify(); 
    
  3. Оба блока должны быть «синхронизированы» на this объекта, чтобы иметь возможность aquire это монитор (который необходим для wait). Вам нужно либо объявить методы «синхронизированными», либо поместить соответствующие блоки внутри блока synchronized(this) {...}.

+0

сервер вызывает метод receiveData для отправки полей и их соответствующих значений ко мне, по одному за раз. Таким образом, существует 60 полей, и поэтому сервер вызывает этот метод 60 раз. Поэтому я думаю, что это то, что вы сказали, поскольку сервер использует Java Socket, который, я думаю, похож на «другой поток». Да? – rallison

+0

В принципе, сервер не может просто «вызвать getData». Я предполагаю, что вы используете какую-то структуру для этой задачи. И эта инфраструктура принимает данные сервера и вызывает ваши методы. Во всяком случае, это ничего не меняет. Судя по вашему описанию, у вас есть 2 отдельных потока, поэтому этот подход является самым простым способом «подождать» для этих данных. – bezmax

+0

Я упустил детали, пытаясь упростить мой вопрос, но я понимаю вашу точку зрения. Технически ServerRequestMethods также предоставляет конструктор, который принимает в качестве параметра ServerDeliveryMethods. Затем в конструкторе MyApp я инициализирую переменную экземпляра: myServerRequestMethodsInstance = new ServerRequestMethods (this). Тогда в основном фактический вызов - myServerRequestMethodsInstance.requestData(). Таким образом, классы запроса/приема связаны, и сервер действительно просто вызывает getData, хотя я не уверен в деталях. Но я думаю, что это все еще ничего не меняет. Спасибо! – rallison

1

Я думаю, что самый эффективный метод - с ожиданием и уведомлением. Вы можете установить поток во сне с wait(). Вы можете пробудить поток от другого, например. ваш сервер с notify(), чтобы проснуться. wait() - метод блокировки, вам не нужно ничего опросить. Вы также можете использовать статический метод Thread.sleep(milliseconds), чтобы подождать некоторое время. Если вы ставите сон в бесконечный цикл, проверяя состояние с непрерывным временем ожидания, вы тоже будете ждать.

Я предпочитаю wait() и notify(), его наиболее эффективно вообще.

-2

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

public static void delay(int time) { 
    long endTime = System.currentTimeMillis() + time; 
    while (System.currentTimeMillis() < endTime) 
    { 
     // do nothing 
    } 
} 

Это получает текущее время и устанавливает время окончания (текущее время + время ожидания) и ждет, пока текущее время не попадает в конечное время.

+0

Это супер неэффективное решение, поэтому не делайте этого – gyurix

0

Довольно старый вопрос, но я искал аналогичную проблему и нашел решение.
Сначала разработчик никогда не должен создавать поток, который будет ждать вечно. Вам действительно нужно создать «условие выхода», если вы используете цикл «while». Кроме того, ждать «InterruptedException» сложно. Если другой поток не вызывает вашThread.interrupt(), вы будете ждать завершения программы. я java.util.concurrent.CountDownLatch так коротко:

/*as field*/ 
CountDownLatch semaphore = new CountDownLatch(1); 

/*waiting code*/ 
boolean timeout = !semaphore.await(10, TimeUnit.SECONDS); 

/*releasing code*/ 
semaphore.countDown(); 

В результате, «ожидание кода» нить будет ждать, пока «освобождающего кода» каком-то другом звонки резьбонакатных или будут «тайм-аут». Если вы хотите подождать 10 полей для заполнения, используйте «новый CountDownLatch (10)».
Этот принцип похож на «java.util.concurrent.Semaphore», но семафор лучше блокирует доступ, и это не ваш случай.

Смежные вопросы