SWTException:无效的线程访问

时间:2014-10-21 07:39:52

标签: java concurrency swt wizard eclipse-plugin

我在创建java项目时使用向导,如果我第一次在空工作区中运行它,则会获得无效的线程访问异常。我尝试实现类似于JavaProjectWizard的向导,但我不需要第二页,因此我尝试从第一页执行完成并提前初始化第二页:

import org.eclipse.jdt.ui.wizards.NewJavaProjectWizardPageTwo;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;

public class SomeNewWizard
    extends Wizard
    implements INewWizard {

    private SomeWizardPageTwo javaWizardPageTwo;

    @Override
    public void addPages() {
            if (javaWizardPageTwo == null)
                    someWizardPageTwo = new SomeWizardPageTwo(newSeeAppWizardPageOne);
    }

    @Override
    public boolean performFinish() {
/*line 109*/someWizardPageTwo .createProvisonalProject();
            final IWorkspaceRunnable op = new IWorkspaceRunnable() {
                    public void run(IProgressMonitor monitor)
                            throws CoreException, OperationCanceledException {
                            try {
                                    someWizardPageTwo.performFinish(new SubProgressMonitor(monitor, 1));
                            }
                            catch (InterruptedException e) {
                                    throw new OperationCanceledException(e.getMessage());
                            }
                            finally {
                                    monitor.done();
                            }
                    }
            };
            try {
                    rule = null;
                    Job job = Job.getJobManager().currentJob();
                    if (job != null)
                            rule = job.getRule();
                    IRunnableWithProgress runnable = new IRunnableWithProgress() {
                            @Override
                            public void run(IProgressMonitor monitor)
                                    throws InvocationTargetException, InterruptedException {
                                    try {
                                            JavaCore.run(op, rule, monitor);
                                    }
                                    catch (OperationCanceledException e) {
                                            throw new InterruptedException(e.getMessage());
                                    }
                                    catch (CoreException e) {
                                            throw new InvocationTargetException(e);
                                    }
                            }
                    };
                    getContainer().run(true, true, runnable);
            }
            catch (InvocationTargetException e) {
                    handleFinishException(getShell(), e);
                    return false;
            }
            catch (InterruptedException e) {
                    return false;
            }
            return true;
    }

public class SomeWizardPageTwo
    extends NewJavaProjectWizardPageTwo
{

    private NewJavaProjectWizardPageOne mainPage;


    public SomeWizardPageTwo(NewJavaProjectWizardPageOne mainPage)
    {
        super(mainPage);
        this.mainPage = mainPage;
    }


    @Override
    public IProject createProvisonalProject()
    {
        return super.createProvisonalProject();
    }


    @Override
    protected IWizardContainer getContainer()
    {
        if (mainPage == null)
            return null;
        return mainPage.getWizard().getContainer();
    }
}

可以找到堆栈跟踪here

问题的根源似乎是ImageDescriptorRegistry是从错误的线程创建的,因为相应的IRunnableWithProgress运行forked。但我想知道为什么它适用于正常的JavaProjectWizard呢?主要问题是:如何使它适用于我的向导?

2 个答案:

答案 0 :(得分:2)

getContainer().run(true, true, runnable);导致runnable在单独的线程中执行。因此,第一个参数fork是负责任的。 对javaWizardPageTwo.performFinish()的调用尝试访问UI线程并导致无效线程访问异常。

如果将fork参数设置为false,则代码将在当前线程上执行。

为什么不直接致电javaWizardPageTwo.performFinish()

答案 1 :(得分:1)

Display.checkDevice中没有错误。

您对NewJavaProjectWizardPageTwo.performFinish的调用正在后台线程中运行,但代码正在使用ImageDescriptorRegistry,需要在用户界面线程上初始化。

这是间歇性的,因为有时您做的其他事情已经初始化了注册表。