Если методы get моделей Swing не ориентированы на многопотоковое исполнение, как Вы обрабатываете их?

Известно, что обновление GUI Swing должно быть сделано исключительно в EDT. Меньше рекламируется, что чтение материала от GUI должно также быть сделано в EDT. Например, давайте возьмем isSelected ButtonModel () метод, который говорит (например), состояние ToggleButton ("вниз" или).

В каждом примере я видел, isSelected() подробно запрашивается от основного или какой бы ни распараллеливают. Но когда я смотрю на реализацию DefaultButtonModel, она не синхронизируется, и значение не энергозависимо. Так, строго говоря, isSelected() мог возвратить мусор, если он читается из какого-либо другого потока, чем тот, от которого он установил (который является EDT, когда пользователь нажимает кнопку). Или действительно ли я ошибаюсь?

Я первоначально думал об этом при испытании на удар объектом № 66 в Эффективном Java Bloch, этом примере:

public class StopThread {
    private static boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while(!stopRequested) i++;
            }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

Вопреки то, что, кажется, та программа никогда не завершается на некоторых машинах, по крайней мере. Обновление stopRequested флаг от основного потока невидим для фонового потока. Ситуация может быть зафиксирована с синхронизируемыми методами get и методами set, или путем установки флага volatile.

Так:

  1. Действительно ли запросы являются состоянием модели Swing вне EDT (строго говоря) неправильно?
  2. В противном случае, каким образом?
  3. Если да, как Вы обрабатываете его? Удачей, или некоторым умным обходным решением? InvokeAndWait?

15
задан Joonas Pulakka 19 January 2010 в 10:13
поделиться

6 ответов

Попытка решить другую проблему, я нашел хорошее решение для этого. Существует личный метод System.configuration.SettingsPropertyValue.ishostedinaspnet , который имеет именно то, что мне нужно. Будучи личным методом, я не хочу называть это (хотя я мог бы использовать отражение), но его реализация тривиальна:

private bool IsHostedInAspnet()
{
    return (AppDomain.CurrentDomain.GetData(".appDomain") != null);
}

(в соответствии с отражателем)

выглядит как специальный ключ в данных домена приложения - «.Appdomain», который устанавливается при запуске в веб-сервере ASP.NET.

Я буду придерживаться этого.

-121--3545652-
  1. Нет, не правда, но, как и в случае любого перекрестного потребления, вам необходимо убедиться, что вы предоставляете соответствующие механизмы безопасности потоков, если вы решите это сделать (например, использование синхронизации или Волатиль ). Например, я обычно пишу свой собственный реализацию Tablemodel , обычно сидящий на списке , где x - мой бизнес-объект. Если я намереваюсь для других потоков для запроса списка, я сделаю это синхронизированную коллекцию . Также стоит отметить, что я никогда не буду нормально обновлять список из других потоков; только запросить это.
  2. Поскольку именно такая же ситуация, как и с любым другим многопоточным приложением.
  3. Я обычно делаю коллекцию синхронизированной (см. 1).

Предостережение

Несмотря на мой ответ выше я, как правило, не модели доступа прямо за пределами EDT. Как упоминается Карл, если действие выполнения обновления вызывается через некоторое действие GUI, нет необходимости выполнять какую-либо синхронизацию, поскольку код уже проходит через EDT. Однако, если я хочу выполнить некоторую фоновую обработку, которая приведет к изменению модели, я обычно вызываю Swingworker , а затем назначить результаты Doinbackground () из из ] Готово () Метод (т.е. на EDT). Это уборщик ИМХО как метод Doinbackground () , не имеет побочных эффектов.

4
ответ дан 1 December 2019 в 04:47
поделиться

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

Обычный совет - запускать потенциально длительные работы (обычно блокирующие) задачи с EDT. Тем не менее, резьба трудна. Swingworker - популярный способ вызвать плохой дизайн - избегать этого. Попробуйте сохранить EDT и код неизведанного кода. Постарайтесь не поделиться мультиремным состоянием.

Ошибки для резьбы сложно. Вы можете не увидеть их на своей машине, но клиенты вполне могут сделать. Возможно, ошибки появляются из-за оптимизации в более поздних версиях JRE. Резьбовые ошибки трудно отслеживать. Поэтому будьте консервативными. Даже блокируя EDT кратко, лучше, чем противные ошибки.

2
ответ дан 1 December 2019 в 04:47
поделиться
  1. Я никогда не беспокоился об этом, но строго говоря, да, вероятно, неверно.
  2. n / a.
  3. Я позволил изменениям в моделях обновления GUI (через слушателей) моего собственного строительства, которые не содержатся или построены качанием. Там никогда не нужно просить графический интерфейс, потому что GUI обновляет модель.

Так как я сам создаю модели (это может быть что-то очень простое, например, как строка с Getter / Setter и PropertyChangeSupport), я могу сделать доступ к доступ к синхронизации, если я хочу. Я редко столкнулся с Flaky поведением из-за контента или такого.

1
ответ дан 1 December 2019 в 04:47
поделиться

Да это неправильно; Если только нитки не синхронизируются на одном и том же объекте, либо используют какой-то другой барьер памяти, как летучие, как определено JMM , или другое, может наблюдать заметное содержимое памяти. Период. Конец истории. Нарушение Это может работать над некоторыми, даже многими, архитектурами, но в конечном итоге укусит вас в Хине.

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

И стоит отметить, что JMM (модель памяти Java) изменилась с JSR-133 в Java 5 очень важными способами, поэтому поведение с J4 и более ранним JVM вполне может уступать разные результаты, чем J5, а затем. Пересмотренный JMM, как вы ожидаете, значительно улучшился.

4
ответ дан 1 December 2019 в 04:47
поделиться

Если да, как вы справляетесь с этим? Удачи, или по некоторым умным обстоятельстве? Invokeandwait?

Другие уже упоминали Swingworker , и вы уже знаете о методах . javax.swing.timer также может быть полезен. Нет серебряных пуль для безопасного многопоточного программирования, хотя хороший дизайн будет иметь большое значение.

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

  public static class ThreadUnsafeAccessException extends RuntimeException {
    private static final long serialVersionUID = 1L;
  }

  @Override public Object getElementAt(int index) {
    if (!SwingUtilities.isEventDispatchThread()) {
      throw new ThreadUnsafeAccessException();
    }
    return decorated.getElementAt(index);
  }

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

1
ответ дан 1 December 2019 в 04:47
поделиться

Это отличный вопрос и обезьяна программного обеспечения имеет правильный ответ. Если вы хотите сделать эффективную резьбу, вы должны полностью понять память Java модель (JMM). Обратите внимание, что модель памяти Java изменилась с JSR-133, поэтому много старых резьбовых примеров, которые вы найдете, будет просто ошибаться. E.G., Волатильное ключевое слово изменилось от того, что он практически бесполезно, чтобы теперь находиться почти как исполнение в качестве синхронизированного ключевого слова.

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

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

О да, у Адамски это правильно. Используйте Swingworker , чтобы убедиться, что длинный рабочий код выполнен в фоновом потоке, и что, когда он выполняется манипулирование данными, он должен доступать доступа к качению на методе () [) . Если вам нужно прочитать, сделайте это до , что делает ваш Swingworker и сделать информацию Final .

Пример кода, который был бы вызван на EDT, скорее всего в Acceplistener или Somesuch (PSuedoCode):

public void someOverlySimpleExampleThatIsCalledOnEDT() {
   /*
    * Any code run here is guaranteed to happen-before 
    * the start of a background thread.
    */
   final String text = myTextField().getText();
   SwingWorker sw = new SwingWorker() {
      private volatile List data;
      public Object doInBackground() {
         //happens in background thread. No Swing access
         data = myDao.getDataFromInternet(text);
         return null;
      }
      public void done() {
         //Happens in EDT. Swing away Merrill
         loadDataIntoJTable(data);
      }
   }
   sw.execute();
   /* 
    * Any code run here happens concurrently with doInBackground(). Be careful. 
    * Usually leave empty
    */
}
0
ответ дан 1 December 2019 в 04:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: