在同步块中使用分叉的 ProgressMonitorDialog

Using forked ProgressMonitorDialog in synchronized block

我正在使用 jface ProgressMonitorDialog 来缓存一些数据。这是在同步块中完成的,以避免 运行 出现并发问题。

但奇怪的是,如果我使用参数 fork=true 调用 ProgressMonitorDialog#运行,同步块将不起作用。

谁能给我解释一下这是怎么回事?

输出:

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());
            }
        }
    }

您正在使用 Display.asyncExec 将两个 doSmth 调用都放入将在 UI 线程中 运行 的 运行 功能列表一旦 Display.readAndDispatch 被调用。

所以第一个调用doSmth运行s就进入了synchronized块。

然后调用 pmd.run fork true。此 运行 在单独的线程中启用 运行 并且还重复调用 Display.readAndDispatch 以保持 UI 线程响应。

这些 Display.readAndDispatch 调用将接收对 doSmth 的第二次调用 - 但您仍在同步块内并且仍在同一个 UI 线程上,因此 synchronized不会阻塞,您会得到观察到的结果。

如果您想 运行 在后台使用代码,请使用 Job 并指定 'scheduling rule' 以防止同时从 运行ning 产生任何冲突的第二个作业.如果作业中有 setUser(true),它将显示一个进度对话框。