Java Swing EDT и параллелизм - PullRequest
4 голосов
/ 27 июля 2011

Мне просто интересно, нужно ли по-прежнему обеспечивать синхронность в invokeLater () Runnable.

Я сталкиваюсь с тупиком и мне нужно преодолеть его при сохранении параллелизма.

Было быпример хорошего кода?:

private String text;

private void updateText()
{
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            synchronized(FrameImpl.this)
            {
                someLabel.setText(text);
            }
        }
    });
}

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

Это правильное решение или я непреднамеренно создаю проблему взаимоблокировки, отправляя синхронизированный код в неизвестный контекст ..?

Спасибо.

Ответы [ 2 ]

7 голосов
/ 27 июля 2011

Лучшим решением было бы что-то вроде этого:

public class Whatever {
    private String text;
    private final Object TEXT_LOCK = new Object();

    public void setText(final String newText) {
        synchronized (TEXT_LOCK) {
            text = newText;
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                someLabel.setText(newText);
            }
        });
    }

    public String getText() {
        synchronized (TEXT_LOCK) {
            return text;
        }
    }
}

Это гарантирует, что если два потока попытаются вызвать setText одновременно, то они не будут сжимать друг друга.Первый поток установит значение text и поставит в очередь обновление пользовательского интерфейса с этим значением.Второй поток также установит значение text и поставит в очередь второе обновление пользовательского интерфейса.

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

Пара замечаний:

  1. Использование отдельного объекта блокировки (т. Е. TEXT_LOCK) означает, что вы не уязвимы для кодагде-то еще блокировка монитора на экземпляре Whatever и непреднамеренная блокировка.Лучше всего всегда держать жесткий контроль над вашими объектами блокировки.Также лучше минимизировать размер ваших синхронизированных блоков.
  2. Вы могли бы сделать весь метод setText синхронизированным, с учетом предостережения, что он потенциально делает вас уязвимым для тупиковой ситуации, как указано выше..
  3. Чтение значения text также необходимо синхронизировать, даже если Strings неизменны.У модели памяти Java есть тонкости, которые означают, что вам всегда необходимо синхронизировать переменные, которые могут быть прочитаны / записаны несколькими потоками.

Проверьте Java Брайана ГетцаПрактический параллелизм для глубокого погружения в сложные части параллелизма (включая странность модели памяти).

0 голосов
/ 27 июля 2011

теперь это будет правильно, весь вывод из задачи должен быть перенесен в InvokeLater (), другой пример обновления GUI из заданий BackGround: здесь

private String text;

private void updateText() {

    synchronized (FrameImpl.this) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                someLabel.setText(text);
            }
        });
    }
}
...