Использование разветвленного ProgressMonitorDialog в синхронизированном блоке - PullRequest
0 голосов
/ 07 января 2020

Я использую jface ProgressMonitorDialog для кэширования некоторых данных. Это делается в синхронизированном блоке, чтобы не столкнуться с проблемами параллелизма.

Как ни странно, синхронизированный блок не работает, если я вызываю ProgressMonitorDialog # run с параметром fork = true.

Может кто-нибудь объяснить мне, что здесь происходит?

Вывод:

start synchronization Thread[main,5,main]
start synchronization Thread[main,5,main]
finished synchronization Thread[main,5,main]
finished synchronization Thread[main,5,main]

Код:

    private void test() {
        Shell shell = new Shell();
        SyncTest st = new SyncTest(shell);

        shell.getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                st.doSmth();
            }
        });
        shell.getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                st.doSmth();
            }
        });
    }

    private static class SyncTest {
        private static final Object LOCK = new Object();

        private Shell shell;

        public SyncTest(Shell shell) {
            this.shell = shell;
        }

        public void doSmth() {
            synchronized (LOCK) {
                System.out.println("start synchronization " + Thread.currentThread().toString());
                try {
                    ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
                    pmd.run(true, true, new IRunnableWithProgress() {
                        @Override
                        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                            Thread.sleep(1000);
                        }
                    });
                } catch (InvocationTargetException | InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("finished synchronization " + Thread.currentThread().toString());
            }
        }
    }

1 Ответ

1 голос
/ 07 января 2020

Вы используете Display.asyncExec для помещения обоих вызовов doSmth в список исполняемых файлов, которые будут выполняться в потоке пользовательского интерфейса, как только будет вызван Display.readAndDispatch.

Итак, первый вызов на doSmth запускается и входит в синхронизированный блок.

Затем он вызывает pmd.run с помощью fork true. Это запускает runnable в отдельном потоке, а также многократно вызывает Display.readAndDispatch, чтобы поддерживать поток пользовательского интерфейса отзывчивым.

Эти Display.readAndDispatch вызовы вызовут второй вызов doSmth - но вы все еще находитесь в синхронизированном блоке и все еще в том же потоке пользовательского интерфейса, поэтому synchronized не блокируется, и вы получаете наблюдаемый результат .

Если вы хотите запускать код в фоновом режиме, используйте Job и укажите «правило планирования», чтобы предотвратить одновременное выполнение любого конфликтующего второго задания. Если у вас есть setUser(true) в работе, он отобразит диалоговое окно прогресса.

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