Showing posts with label eclipse. Show all posts
Showing posts with label eclipse. Show all posts

Monday, April 19, 2010

Eclipse RCP中多线程Job使用

更多精彩请到 http://www.139ya.com

http://faithful-czx.javaeye.com/blog/378800

Eclipse RCP中多线程Job使用
本文分析了Eclipse中多线程程序的实现,讨论了在Eclipse客户端程序开发中应用多线程的方法和要注意的问题,同时也讨论了多线程程序的一些调试和问题解决的方法。
Eclipse 作为一个开发平台,使用越来越广泛,基于Eclipse Rich Client Platform开发的客户端程序也越来越多。在当今越来越复杂的应用环境中,我们的客户端程序不可避免的要同时进行多任务的处理。一个优异的客户端程序都会允许用户同时启动多个任务,从而大大提高用户的工作效率以及用户体验。本文中我们来谈谈Eclipse中实现多任务的方式。

在我们基于Eclipse的Java程序中,我们有很多种方式提供多任务的实现。熟悉Java的朋友立即会想到Java的Thread类,这是 Java中使用最多的一个实现多任务的类。Eclipse平台为多任务处理提供了自己的API,那就是Job以及UIJob。Eclipse中的Job是对Java Thread的一个封装,为我们实现多任务提供了更方便的接口。以下是Job的基本用法:

清单 1. Job用法示例


Job job = new Job(“Job Name”){
protected IStatus run(IProgressMonitor monitor) {

// 在这里添加你的任务代码
return Status.OK_STATUS;
}
};
job.schedule(1133);//delaytime
job.setUser(true);//if true show UI
job.setPriority(priority)




在Eclipse 中我们也会经常用到Display.asynchExec() 和Display.synchExec()来启动任务的执行。这两个方法主要为了方便我们完成界面操作的任务。以下是 Display.asynchExec()的用法,Display.synchExec()和它类似。


清单 2. Display.synchExec()用法示例
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// 在这里添加你的任务代码
}
});



通常,在Eclipse中我们最好使用Eclipse提供的Job接口来实现多任务,而不是使用Java的thread。为什么呢?主要有以下几个原因:

Job是可重用的工作单元,一个Job我们可以很方便的让它多次执行。 Job提供了方便的接口,使得我们在处理中能够很方便的与外界交流,报告当前的执行进度 Eclipse提供了相应的机制使得程序员可以方便的介入Job的调度,例如我们可以方便的实现每次只有一个同一类型的Job在运行 Eclipse缺省提供了Job管理的程序,可以查看当前所有的Job和它们的进度,也提供UI终止、暂停、继续指定的Job 使 用Job可以提高程序的性能,节省线程创建和销毁的开销。Eclipse中的Job封装了线程池的实现。当我们启动一个Job时,Eclipse不会马上 新建一个Thread,它会在它的线程池中寻找是否有空闲的线程,如果有空闲线程,就会直接用空闲线程运行你的Job。一个Job终止时,它所对应的线程 也不会立即终止,它会被返回到线程池中以备重复利用。这样,我们可以节省创建和销毁线程的开销 下面我们从几个方面来讨论Eclipse中Job的实现和使用方面的问题。

Eclipse中Job的实现

Eclipse 的核心包中提供了一个JobManager类,它实现了IJobManager接口,Eclipse中Job的管理和调度都是由JobManager来实现的。 JobManager维护有一个线程池,用来运行Job。当我们调用Job的schedule方法后,这个Job会被JobManager首先放到一个 Job运行的等待队列中去。之后,JobManager会通知线程池有新的Job加入了运行等待队列。线程池会找出一个空闲的线程来运行Job,如果没有空闲线程,线程池会创建一个新的线程来运行Job。一旦Job运行完毕,运行Job的线程会返回到线程池中以备下次使用。从上面Job运行的过程我们可以看到,JobManager介入了一个Job运行的全过程,它了解Job什么时候开始,什么时候结束,每一时候Job的运行状态。JobManager将这些Job运行的信息以接口的方式提供给用户,同时它也提供了接口让我们可以介入Job的调度等,从而我们拥有了更加强大的控制Job的能力。

为了我们更方便的了解Job所处的状态,JobManager设置Job的一个状态标志位,我们可以通过Job的getState方法获得Job 当前的状态值以了解其状态:

NONE:当一个Job刚构造的时候,Job就会处于这种状态。当一个Job执行完毕(包括被取消)后,Job的状态也会变回这种状态。 WAITING:当我们调用了Job的shedule方法,JobManager会将Job放入等待运行的Job队列,这时Job的状态为 WAITING. RUNNING:当一个Job开始执行,Job的状态会变为RUNNING。 SLEEPING: 当我们调用Job的sleep方法后,Job会变成这一状态。当我们调用schudule方法的时候带上延时的参数,Job的状态也会转入这一状态,在这 一段延时等待的时间中,Job都处于这一状态。这是一种睡眠状态,Job在这种状态中时不能马上转入运行。我们可以调用Job的wakeup方法来将 Job唤醒。这样,Job又会转入WAITING状态等待运行。
Eclipse中的UI线程

另外,在Eclipse的线程处理中,有一个UI线程的概念。Eclipse程序中的主线程是一个特殊的线程,程序启动后会先执行这个线程,也就是我们的 main()函数所在的线程。作为桌面应用程序,我们的主线程主要负责界面的响应以及绘制界面元素,所以通常我们也叫它UI线程。

以下代码,编过SWT应用程序的读者会非常熟悉。它一般出现在main函数的结尾。下面来仔细分析一下它的详细情况。

//当窗口未释放时
while (!shell.isDisposed()) {

//如果display对象事件队列中没有了等待的事件,就让该线程进入等待状态
if (!display.readAndDispatch())
display.sleep();

}




上面的程序实际上就是我们UI线程的处理逻辑:当程序启动后,UI线程会读取事件等待队列,看有没有事件等待处理。如果有,它会进行相应处理,如果没有它会进入睡眠状态。如果有新的事件到来,它又会被唤醒,进行处理。UI线程所需要处理的事件包括用户的鼠标和键盘操作事件,操作系统或程序中发出的绘制事件。一般来说,处理事件的过程也就是响应用户操作的过程。

一个好的桌面应用程序需要对用户的操作作出最快的响应,也就是说我们的UI线程必须尽快的处理各种事件。从我们程序的角度来说,在UI线程中我们不能进行大量的计算或者等待,否则用户操作事件得不到及时的处理。通常,如果有大量的计算或者需要长时间等待(例如进行网络操作或者数据库操作)时,我们必须将这些长时间处理的程序单独开辟出一个线程来执行。这样虽然后台运行着程序,但也不会影响界面上的操作。

除主线程之外的所有线程都是非UI线程。在Eclipse程序中,我们所有对界面元素的操作都必须放到UI线程中来执行,否则会抛出 Exception,所以我们要区分出UI线程和非UI线程,保证我们对UI的操作都在UI线程中执行。

如何判断当前线程是否UI线程: 你可以通过调用Display.getCurrent()来知道当前线程是否是UI线程。如果Display.getCurrent()返回为空,表示当前不是UI线程。


Eclipse中使用线程的几种典型情况

控制Job的并发运行 对于某些Job,为了避免并发性问题,我们希望同时只有一个这样的Job在运行,这时我们需要控制Job的并发运行。在另一种情况下,我们也需要控制 Job 的并发运行:我们在程序中对于一个任务,我们有可能会启动一个Job来执行,对于少量的任务来说,这是可行的,但是如果我们预测可能会同时有大量的任务,如果每一个任务启动一个Job,我们同时启动的Job就会非常多。这些Job会侵占大量的资源,影响其他任务的执行。我们可以使用Job的rule来实现控制Job的并发执行。简单的我们可以通过下面的代码实现。我们先定义一个如下rule:

private ISchedulingRule Schedule_RULE = new ISchedulingRule() {
public boolean contains(ISchedulingRule rule) {
return this.equals(rule);
}
public boolean isConflicting(ISchedulingRule rule) {
return this.equals(rule);
}
};




对于需要避免同时运行的Job,我们可以将它们的rule设成上面定义的rule。如:

myjob1.setRule(Schedule_RULE);
myjob2.setRule(Schedule_RULE);




这样对于myjob1和myjob2这两个Job,它们不会再同时执行。Myjob2会等待myjob1执行完再执行。这是由Eclipse的 JobManager来提供实现的。JobManager可以保证所有启动的Job中,任意两个Job的rule是没有冲突的。我们在上面定义的rule 是最简单的。我们可以重写isConflicting函数来实现一些更加复杂的控制,比如控制同时同类型的Job最多只有指定的个数在运行。但是我们要注意,isConflicting方法不能过于复杂。一旦一个Job的rule与其他Job的rule有冲突,isConflicting方法会调用很多次。如果其中的计算过于复杂,会影响整体的性能。

根据需要执行Job 由于我们有的Job有可能不是立即执行的,在有些情况下,等到该Job准备执行的时候,该Job所要执行的任务已经没有意义了。这时,我们可以使用Job 的 shouldSchedule()和shouldRun()来避免Job的运行。在我们定义一个Job时,我们可以重载shouldSchedule和 shouldRun方法。在这些方法中,我们可以检查Job运行的一些先决条件,如果这些条件不满足,我们就可以返回false。JobManager在安排Job运行时,它会先调用该Job的shouldSchedule方法,如果返回为false,JobManager就不会再安排这个Job运行了。同样,JobManager在真正启动一个线程运行一个Job前,它会调用该Job的shouldRun方法,如果返回false,它不再运行这个 Job。在下面的例子中,我们希望启动一个Job在十秒钟之后更新文本框中的内容。为了保证我们的Job运行时是有意义的,我们需要确保我们要更新的文本框没有被销毁,我们重载了shouldSchedule和shouldRun方法。

Text text = new Text(parent,SWT.NONE);
UIJob refreshJob = new UIJob(“更新界面”){
public IStatus runInUIThread(IProgressMonitor monitor) {

text.setText(“新文本”);
return Status.OK_STATUS;
}
public boolean shouldSchedule(){
return !text.isDisposed();
}
public boolean shouldRun(){
return !text.isDisposed();
}
};
refreshJob.schedule(10000);



在UI线程中涉及长时间处理的任务 我们经常碰到这样一种情况:用户操作菜单或者按钮会触发查询大量数据,数据查询完后更新表格等界面元素。用户点击菜单或者按钮所触发的处理程序一般处于 UI 线程,为了避免阻塞UI,我们必须把数据查询等费时的工作放到单独的Job中执行,一旦数据查询完毕,我们又必须更新界面,这时我们又需要使用UI线程进行处理。下面是处理这种情况的示例代码:

button.addSelectionListener(new SelectionListener(){
public void widgetSelected(SelectionEvent e){
perform();
}

public void widgetDefaultSelected(SelectionEvent e){
perform();
}

private void perform(){
Job job = new Job(“获取数据”){
protected IStatus run(IProgressMonitor monitor){
// 在此添加获取数据的代码
Display.getDefault().asyncExec(new Runnable(){
public void run(){
// 在此添加更新界面的代码
}
});
}
};
job.schedule();
}

});

延时执行Job,避免无用的Job运行 我们经常需要根据选中的对象刷新我们部分的界面元素。如果我们连续很快的改变选择,而每次刷新界面涉及到的区域比较大时,界面会出现闪烁。从用户的角度来说,我们很快的改变选择,希望看到的只是最后选中的结果,中间的界面刷新都是不必要的。

在Jface 中,StructuredViewer提供了addPostSelectionChangedListener方法。如果我们使用这个方法监听 selectionChanged事件,当用户一直按着方向键改变选中时,我们只会收到一个selectionChanged事件。这样我们可以避免过度的刷新界面。

实际上,Jface中就是通过延时执行Job来实现这一功能的。我们也可以自己实现类似功能:

private final static Object UPDATE_UI_JOBFAMILY = new Object();
tableviewer. addSelectionChangedListener (new ISelectionChangedListener (){

public void selectionChanged(SelectionChangedEvent event){
Job.getJobManager().cancel(UPDATE_UI_JOBFAMILY);
new UIJob("更新界面") {
protected IStatus runInUIThread (IProgressMonitor monitor) {
//更新界面
return Status.OK_STATUS;
}

public boolean belongsTo(Object family){
return family== UPDATE_UI_JOBFAMILY;
}

}.schedule(500);
}
});



首先,我们需要将界面更新的代码放到一个UIJob中,同时我们将Job延时500毫秒执行(我们可以根据需要改变延时的时间)。如果下一个 selectionChanged事件很快到来,我们的调用Job.getJobManager().cancel (UPDATE_UI_JOBFAMILY)将以前未运行的Job取消,这样只有最后一个Job会真正运行。

在UI线程中等待非UI线程的结束 有时,我们在UI线程中需要等待一个非UI线程执行完,我们才能继续执行。例如,我们在UI线程中要显示某些数据,但是这些数据又需要从数据库或者远程网络获取。于是,我们会启动一个非UI的线程去获取数据。而我们的UI线程必须要等待这个非UI线程执行完成,我们才能继续执行。当然,一种简单的实现方法是使用join。我们可以在UI线程中调用非UI线程的join方法,这样我们就可以等待它执行完了,我们再继续。但是,这会有一个问题。当我们的UI线程等待时,意味着我们的程序不会再响应界面操作,也不会刷新。这样,用户会觉得我们的程序象死了一样没有反应。这时,我们可以使用 ModalContext 类。你可以将你要执行的获取数据的任务用ModalContext的run方法来运行(如下)。ModalContext会将你的任务放到一个独立的非 UI线程中执行,并且等待它执行完再继续执行。与join方法不同的是,ModalContext在等待时不会停止UI事件的处理。这样我们的程序就不会没有响应了。

try {
ModalContext.run(new IRunnableWithProgress(){
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
/*需要在非UI线程中执行的代码*/
ModalContext.checkCanceled(monitor);
}
}, true, new NullProgressMonitor(), Display.getCurrent());
} catch (InvocationTargetException e) {

} catch (InterruptedException e) {
}



针对相关联的Job统一进行处理 有时,我们需要对相关联的Job一起处理。例如需要同时取消这些Job,或者等待所有这些Job结束。这时我们可以使用Job Family。对于相关联的Job,我们可以将它们设置成同一个Job Family。我们需要重载Job的belongsTo方法以设置一个Job的Job Family。

Private Object MY_JOB_FAMILY = new Object();
Job job = new Job(“Job Name”){
protected IStatus run(IProgressMonitor monitor) {
// 在这里添加你的任务代码
return Status.OK_STATUS;
}

public boolean belongsTo(Object family){
return MY_JOB_FAMILY.equals(family);
}
};



我们可以使用JobManager的一系列方法针对Job Family进行操作:

Job.getJobManager().cancel(MY_JOB_FAMILY); //取消所有属于MY_JOB_FAMILY的所有Job
Job.getJobManager().join(MY_JOB_FAMILY); //等待属于MY_JOB_FAMILY的所有Job结束
Job.getJobManager().sleep(MY_JOB_FAMILY); //将所有属于MY_JOB_FAMILY的Job转入睡眠状态
Job.getJobManager().wakeup(MY_JOB_FAMILY); //将所有属于MY_JOB_FAMILY的Job唤醒




线程死锁的调试和解决技巧

一旦我们使用了线程,我们的程序中就有可能有死锁的发生。一旦发生死锁,我们发生死锁的线程会没有响应,导致我们程序性能下降。如果我们的UI线程发生了死锁,我们的程序会没有响应,必须要重启程序。所以在我们多线程程序开发中,发现死锁的情况,解决死锁问题对提高我们程序的稳定性和性能极为重要。

如果我们发现程序运行异常(例如程序没有响应),我们首先要确定是否发生了死锁。通过下面这些步骤,我们可以确定是否死锁以及死锁的线程:

在Eclipse中以Debug模式运行程序 执行响应的测试用例重现问题 在Eclipse的Debug View中选中主线程(Thread[main]),选择菜单Run->Suspend。这时Eclipse会展开主线程的函数调用栈,我们就可以看到当前主线程正在执行的操作。 通常,Eclipse在等待用户的操作,它的函数调用栈会和以下类似:


图片示例


如果主线程发生死锁,函数调用栈的最上层一般会是你自己的函数调用,你可以查看一下你当前的函数调用以确定主线程在等待什么 使用同样的方法查看其他线程,特别是那些等待UI线程的线程 我们需要找出当前线程相互的等待关系,以便找出死锁的原因。我们找出死锁的线程后就可以针对不同情况进行处理:

减小锁的粒度,增加并发性 调整资源请求的次序 将需要等待资源的任务放到独立的线程中执行
Job使用中要注意的问题

不 要在Job中使用Thread.sleep方法。如果你想要让Job进入睡眠状态,最好用Job的sleep方法。虽然,使用Thread.sleep和 Job的sleep方法达到的效果差不多,但是它们实现的方式完全不同,对系统的影响也不一样。我们知道Eclipse中Job是由Eclipse的 JobManager来管理的。如果我们调用Job的sleep方法,JobManager会将Job转入睡眠状态,与其对应的线程也会重新放入线程池等 待运行其他Job。而如果我们在Job中直接调用Thread.sleep方法,它会直接使运行Job的线程进入睡眠状态,其他Job就不可能重用这个线 程了。同时,虽然运行该Job的线程进入了睡眠状态,Job的状态还是Running(运行状态),我们也不能用Job的wakeup方法唤醒该Job了 Job 的取消。一般我们会直观的认为,一旦调用Job的cancel方法,Job就会停止运行。实际上,这并不一定正确,当Job处于不同的状态时,我们调用 Job的cancel方法所起的效果是不同的。当Job在WAITING状态和SLEEPING状态时,一旦我们调用cancel方法, JobManager会将Job直接从等待运行的队列中删除,Job不会再运行了,这时cancel方法会返回true。但是如果Job正在运行, cancel方法调用并不会立即终止Job的运行,它只会设定一个标志,指明这个Job已经被取消了。我们可以使用Job的run方法传入的参数 IProgressMonitor monitor,这个参数的isCanceled方法会返回Job是否被取消的状态。如果需要,我们必须在我们的代码的适当位置检查Job是否被取消的标 志,作出适当的响应。另外,由于调用Job的cancel方法不一定立即终止Job,如果我们需要等待被取消的Job运行完再执行,我们可以用如下代码: if (!job.cancel())
job.join();


Join方法的使用。由于join方法会导致一个线程等待另一个线程,一旦等待线程中拥有一个被等待线程所需要的锁,就会产生死锁。当我们的线程中需要用到同步时,这种死锁的情况非常容易出现,所以我们使用join时必须非常小心,尽量以其他方法替代。 避 免过时的Job造成的错误。由于我们启动的线程并不一定是马上执行的,当我们的Job开始运行时,情况可能发生了变化。我们在Job的处理代码中要考虑到 这些情况。一种典型的情况是,我们在启动一个对话框或者初始化一个ViewPart时,我们会启动一些 Job去完成一些数据读取的工作,一旦数据读取结束,我们会启动新的UI Job更新相应的UI。有时,用户在打开对话框或者View后,马上关闭了该对话框或者View。这时我们启动的线程并没有被中断,一旦在Job中再去更 新UI,就会出错。在我们的代码中必须作相应的处理。所以,我们在线程中更新界面元素之前,我们必须先检查相应的控件是否已经被dispose了 结束语

在我们进行基于Eclipse的客户端开发时,使用多线程可以大大的提供我们的程序并发处理能力,同时对于提高用户体验也有很好的帮助。但是,多线程程序也有其不利的一面,我们也不要滥用线程:

首先,多线程程序会大大的提高我们程序的复杂度,使得我们的开发和调试更加困难 其次,过多的线程容易引发死锁、数据同步等并发问题的发生 另外,由于线程创建和销毁需要开销,程序的整体性能可能因为过多线程的使用而下降 所以,我们在使用线程时一定要谨慎。本文对Eclipse线程的讨论,希望能对大家使用线程有所帮助。由于实际情况较为复杂,文中所提到的方法仅供参考,读者对于不同的实际问题需要进行具体分析,从而找出最佳的解决方案。

Display与Shell

更多精彩请到 http://www.139ya.com

http://hoodman.javaeye.com/blog/497262

一个SWT程序至少需要一个Display对象,创建Display的线程称为UI线程,一个线程中不能有两个Display。
第一次调用Display.getDefault()会创建一个Display,以后再次调用会返回创建的Display。
或者显式定义一个Display:Display dis=new Display(),以后调用getdefault()也会返回创建的Display。

多线程程序中,采用Display.getCurrent()可以获取当前线程的Display,调用 Display.findDisplay(Thread)可以找到任意线程的Display。
在多线程中不要使用getDefault(),容易导致非法线程访问异常。

Shell代表一个窗口,可以基于Display创建Shell,或者基于父Shell创建子shell,若父shell被关闭,子Shell也自动关闭。

使用Display.getMonitors()可以获取与Display相关的所有监视器,getPrimaryMonitor()可以获取主监视器,监视器(Monitor)的边界代表屏幕大小,客户区通常小于监视器尺寸.Monitor.getBounds();monitor.getClientArea(),用于获取边界和客户区。

多线程同步:Display维护一个自定义的事件队列,供后台线程与UI线程同步,后台线程利用Runalble对象插入事件队列,display执行消息循环时就会执行这些操作,Display提供了两个方法向队列中插入事件:
Display.syncExec(),Display.asyncExec()。前者同步调用,通知UI在下一个事件循环时执行Runalble的 run方法,同时线程将被阻塞,直到runable执行完毕,后者为异步调用,区别是线程不会被阻塞,runable执行完毕后不会得到通知。
public static void main(String[] args) {
final Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Hello world!");
final Button button = new Button(shell, SWT.NONE);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Thread thread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(10000);//代表大量运算
} catch (Exception e2) {
// TODO: handle exception
}
display.syncExec(new Runnable() {
@Override
public void run() {
button.setText("finish");//运算完毕,提示通知
}
});
}
};
thread.start();
}
});
button.setText("button");
button.setBounds(20, 15, 155, 25);

shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}

最近的Eclipse plugin开发总结

更多精彩请到 http://www.139ya.com

http://macrochen.javaeye.com/blog/143244

List控件没有提供addDblClickListener方法,如果要处理双击事件,则需要这样处理:


java 代码

1. list.addListener(SWT.MouseDoubleClick, new Listener() {
2. public void handleEvent(Event event) {
3. System.out.println(event);
4. }});

在WizardPage中要实现想到的前进和后退需要这么使用
((WizardDialog)getWizard().getContainer()).showPage(getNextPage());
而不能简单的通过wizardPage的setVisibile()来设置可见和不可见

ed.getCommandStack().execute(command);和 command.execute()是有区别的,前者会告诉editor当前的EditorInput已经发生改变,而后者不会

在保存emf模型的时候,遍历每一个emf节点,都会执行 org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveElementID该方法
保存属性执行 org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveDataTypeSingle(EObject o, EStructuralFeature f)该方法

如何定义扩展点
我们可以给插件定义扩展来增加插件的灵活性,满足用户的定制要求.
每一个扩展点都必须包括一个唯一标识符用来标识当前定义的扩展点,在使用扩展点的时候的扩展点id就是插件全限定+这个唯一标识符,而且每一个扩展点都会关联一个schema文件,该文件用来告诉用户如何使用该扩展点,不过该schema文件不是必须的,但是他可以为我们定义的扩展点进行验证并自动生成相关的文档信息,schema文件以.exsd的格式存放在插件所在目录的schema文件夹下
图片文件之类的,在定义扩展点属性的时候,必须将其kind属性设置为resource,而如果是java类的话,则需要将kind属性设置为java

Display.syncExec() and asyncExec()方法的区别,前者是同步执行,这里的"步"可以理解是管道,也就是在一个管道中挨个执行线程(当前线程+指定线程),后者是异步执行,也就是它可以另起一个管道来执行指定的线程.syncExec在指定的线程执行完毕之后才返回,asyncExec无论指定的线程是否结束都返回到当前的线程

获得IWorkBenchWindow的方法:
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();

得到pluginId要这么用:
CommonPlugin.getDefault().getBundle().getSymbolicName()

根据pluginId得到一个bundle
Bundle bundle = Platform.getBundle(pluginId);

通过调用Display.getCurrent()来知道当前线程是否是UI线程。如果 Display.getCurrent()返回为空,表示当前不是UI线程。只有一个UI线程,其他的都是非UI线程

Job的join方法表示当前job执行完成之后再执行job后面的代码,否则这个顺序是无序的

在非UI线程中调用UI线程会抛出SWTException异常,要解决这个问题需要使用 Display.syncExec()或者asyncExec()方法,还有一种解决方法就是用时UIJob,不过必须复写 runInUIThread()方法,将逻辑代码放在该方法中执行而不是run()方法中

打开对话框查找多个制定类型的文件可以参考 org.eclipse.jdt.internal.ui.wizards.buildpaths.LibrariesWorkbookPage.openExtJarFileDialog() 方法

java.lang.VerifyError: (xxx) Wrong return type in function问题的解决
一般出现这种错误是由于java complier和jre的版本不一致导致的,一般在升级的时候很容易碰到,比如有时候指定在java 1.4下编译,但是实际上我们的程序在java5.0下跑
还有一种可能就是升级之后,原来的类已经从一个包里面移动到另外一个包下面了,而加载classpath的时候存在两份

跟踪键盘事件的时候, 在该方法下加断点void org.eclipse.swt.widgets.TypedListener.handleEvent(Event e)

对于显示tooltip提示信息需要在void org.eclipse.swt.widgets.TypedListener.handleEvent(Event e)中监听SWT.MouseHover类型的事件

aptana js editor中的提示信息的获得通过 com.aptana.ide.editors.unified.hover.LexemeTextHover.getHoverInfo(ITextViewer textViewer, IRegion hoverRegion)
取得

在aptana中对文档的分割使用到Lexme的概念, 而所有的提示, 自动提示功能都是建立在Lexme的基础上的

aptana加载内容提示配置文件在 com.aptana.ide.editor.js.JSLanguageEnvironment中实现

向日志中添加一条出错信息:
IStatus status = new Status(IStatus.ERROR,
"org.eclipse.jface", //$NON-NLS-1$
0, message, new Exception());
Policy.getLog().log(status);

IWorkspace ws = ResourcesPlugin.getWorkspace();用来取得workspace对象

Thursday, December 3, 2009

Eclipse插件开发小结

更多精彩请到 http://www.139ya.com

http://wjj-tt.spaces.live.com/blog/cns!91CCF857592F26C!106.entry

这两天看了一下Eclipse的插件开发,参考的书就是那本著名的Contributing to Eclipse。

把两点体会记录如下:

1、Extension和Extension-point

Extension 和Extension-point是相互关联的,由Extension-point定义插件具备的扩展点并且定义了如何使用这些扩展点(由Schema中 定义),而Extension则是根据扩展点中定义的Schema来描述扩展的内容。Extension定义的是对已有插件进行的扩展,其中point是 扩展源的id。对于不同的扩展源,Extension的元素定义各不相同。Extension-piont定义的是本插件向外提供的扩展功能,利用 Schema来定义Extension。

【学习心得】JFace和SWT有什么区别呢?

更多精彩请到 http://www.139ya.com


JFace:插件的用户界面框架
我们已经见到工作台定义扩展点来为使插件向平台添加用户界面功能。许多这些扩展点,特别是向导扩展,是通过使用 org.eclipse.jface.* 包中的类来实现的。有什么区别?

JFace 是一个用户界面工具箱,它提供很难实现的、用于开发用户界面功能部件的 helper 类。JFace 在原始的窗口小部件系统的级别之上运行。它提供用于处理常见的用户界面编程任务的类:

查看器负责处理填充、排序、过滤和更新窗口小部件等最辛苦的工作。
操作和添加项介绍用于定义用户操作的语义,并指定在何处提供它们。
图像和字体注册表提供用于处理用户界面资源的常见模式。
对话框和向导定义用于构建与用户进行复杂交互的框架。
JFace 使您可以专注于实现特定插件的功能,而不必花费精力来处理底层窗口小部件系统或者解决几乎在任何用户界面应用程序中都很常见的问题。

JFace 和工作台
何处是 JFace 结束而工作台开始的位置?有时候界线并不是这样明显。通常,JFace API(来自于包 org.eclipse.jface.*)独立于工作台扩展点和 API。可以想象,根本不必使用任何工作台代码就可以编写 JFace 程序。

工作台使用 JFace,但是又试图尽可能减少依赖项。例如,工作台部件模型(IWorkbenchPart)被设计为独立于 JFace。我们很早就知道可以直接使用 SWT 窗口小部件来实现视图和编辑器,而不必使用任何 JFace 类。工作台尽可能保持“JFace 中立”,允许程序员使用他们觉得有用的 JFace 的部件。实际上,在工作台的大多数实现中都使用了 JFace,并且在 API 定义中引用了 JFace 类型。(例如,IMenuManager、IToolBarManager 和 IStatusLineManager 的 JFace 接口显示为工作台 IActionBar 方法中的类型。)

JFace 和 SWT
SWT 和 JFace 之间的界线是很明显的。SWT 根本不依赖于任何 JFace 或平台代码。许多 SWT 示例说明可以如何构建独立的应用程序。

JFace 用来在 SWT 库顶部提供常见的应用程序用户界面功能。JFace 并不试图“隐藏”SWT 或者替换它的功能。它提供一些类和接口,以处理与使用 SWT 来对动态用户界面编程相关联的许多常见任务。

通过了解查看器及它们与 SWT 窗口小部件之间的关系,就可以更清楚地了解 JFace 和 SWT 之间的关系。



Java是一种强大的编程语言。但强大就意味复杂,尤其是和Java相关的名词就象天上的星星一样,数都数不过来。在本文中就涉及到两个比较常用的名词 SWT和JFace。在标题中将SWT和JFace放到一起,并不是说SWT和JFace是一个意思,而是说它们的关系非常紧密。

基于Java的图形库最主要的有三种,它们分别是Swing、AWT和SWT。其中前两个是Sun随JDK一起发布的,而SWT则是由IBM领导的开源项目(现在已经脱离IBM了)Eclipse的一个子项目。SWT的执行效率非常高。这是由于SWT的底层是由C编写的。由于SWT通过C直接调用系统层的 GUI API。因此,使用SWT编写GUI程序,在外观上就和使用C++、Delphi(在Windows下)编写的程序完全一样。它的这一点和AWT类似。 AWT在底层也是使用C直接调用系统层的GUI API。但它们是有区别的,最大的区别可能就是一个是Sun提供的,一个是Eclipse自带的。这就意味着如果使用AWT,只要机器上安装了JDK或 JRE,发布软件时无需带其它的库。而如何使用SWT,在发布时必须要自带上SWT的*.dll(Windows版)或*.so(Linux/Unix 版)文件以及相关的*.jar包。还有就是它们所提供的图形接口有一些差异。SWT可能更丰富一些,我们可以看看Eclipse的界面就知道了。但随着 Sun对AWT库的不断更新,AWT的图形表现能力也在不断地提高。

虽然SWT很强大,但它比较底层。也就是说它的一些功能在使用上还比较低级,不太符合面向对象的特征。因此,在SWT的基础上又开发了JFace。JFace在SWT上进行了一定的扩展。因此,也可说JFace是基于 SWT的,就象在VC中使用MFC来包装Win32 API一样。

Wednesday, December 2, 2009

Introduction to Eclipse Plugin Development

更多精彩请到 http://www.139ya.com

From : http://www.eclipsepluginsite.com/index.html

Eclipse Plugin Development TUTORIAL

Eclipse Plugin Development Tutorial website to teach you how to develop eclipse plugins using simple examples to a complex eclipse rcp over time. This chapter will give you a detailed insight into Eclipse Architecture and we will develop a simple but fully functional eclipse plug-in so as to give you a quick start with eclipse plug-in development.

Overview

Eclipse isn’t a huge single java program, but rather a small program which provides the functionality of typical loader called plug-in loader. Eclipse (plug-in loader) is surrounded by hundreds and thousands of plug-ins. Plug-in is nothing but another java program which extends the functionality of Eclipse in some way. Each eclipse plug-in can either consume services provided by other plug-in or can extend its functionality to be consumed by other plug-ins. These plug-in are dynamically loaded by eclipse at run time on demand basis.

An Open Platform

Eclipse is an open platform. It is designed to be easily and infinitely extensible by third parties. At the core is the eclipse SDK, we can build various products/tools around this SDK. These products or tools can further be extended by other products/tools and so on. For example, we can extend simple text editor to create xml editor. Eclipse architecture is truly amazing when it comes to extensibility. This extensibility is achieved by creating these products/tools in form of plug-ins.


Figure 1-1


Inside the Eclipse SDK



Figure 1-2

RCP: On the bottom is RCP which provides the architecture and framework to build any rich client application.

IDE: It is a tools platform and a rich client application itself. We can build various form of tooling by using IDE for example Database tooling.

JDT: It is a complete java IDE and a platform in itself.

PDE: It provides all tools necessary to develop plug-ins and RCP applications. This is what we will concentrate on the course of this tutorial.

Plug-ins everywhere

All the layers in eclipse SDK are made up of plug-ins. If you see all the way, you will notice that everything is a plug-in in eclipse sdk.




Figure 1-3

Plug-in Architecture

A plugin is a small unit of Eclipse Platform that can be developed separately. It must be noted that all of the functionality of eclipse is located in different plugins (except for the kernel)





A plug-in can be delivered as a jar file. A plug-in is self-contained bundle in a sense that it contains the code and resources that it needs to run for ex: code, image files, resource bundles etc. A plug-in is self describing - when I say it is self describing it means that it describes who it is and what it contributes to the world. It also declares what it requires from the world.

A Mechanism For Extensibility

Figure 1-7

We all know that eclipse is extensible. In order to achieve this extensibility eclipse uses the concept of extension points and extension. Think of extension point as Electric socket and think of extension as a plug. Plug-in A exposes a extension point (electric socket) which Plug-in B extends by providing an extension (an electric plug). Plug-in A knows nothing about plug-in B. If we think about it this is very similar to concept of Inheritance – we extend functionality of base class to provide more specific implementation. Think of Plug-in A as a text editor and Plug-in B as xml editor. Text editor declares extension point thereby declaring to the world that it is open for extension and xml editor extends text editor by using its extension point to customize it in its own way. It is important to understand that each extension point essentially declares
a contract. An extension point provider only accepts those extensions which abide by the contract.

These extension points and extensions are declared in plugin.xml (discussed earlier). The runtime is able to wire extensions and extension points and form a registry using markup alone.

Plug-in Example

Now that we have covered good amount of architecture basics, its time to get our hands dirty with some actual plug-in coding. The process for creating a plug-in is best demonstrated by implementing a plug-in on which discussion and examples can be based. Here we will take a step-by-step approach to create a simple but fully operational plug-in. This example will try to give you an feel of eclipse plug-in development. However, don’t try to grab all the details at this point. It is fine if you are not able to understand much of the details in this example. Rest of the tutorial will cover all the topics in great depth.

We will build a simple Resource Manager plug-in. Features of this plug-in are as follows:

  • Ability to add/remove resources (essentially files in workspace) to resource manager.
  • Display list of resources which were added to resource manager.
  • Ability to open up associated editor whenever resource is clicked.



Wednesday, August 5, 2009

Eclipse 启动运行速度调优

更多精彩请到 http://www.139ya.com

转自 : http://www.javaeye.com/wiki/Eclipse/669-Eclipse%20%E5%90%AF%E5%8A%A8%E8%BF%90%E8%A1%8C%E9%80%9F%E5%BA%A6%E8%B0%83%E4%BC%98

JVM 提供了各种用于调整内存分配和垃圾回收行为的标准开关和非标准开关。其中一些设置可以提高 JAVA IDE 的性能。
注意,由于 -X (尤其是 -XX JVM)开关通常是 JVM 或 JVM 供应商特定的,本部分介绍的开关可用于 Sun Microsystems J2SE 1.4.2。

以下设置在大多数系统上将产生比工厂更好的设置性能。
-vmargs - 表示将后面的所有参数直接传递到所指示的 Java VM。

-Xverify:none - 此开关关闭Java字节码验证,从而加快了类装入的速度,并使得在仅为验证目的而启动的过程中无需装入类。此开关缩短了启动时间,因此没有理由不使用它。

-Xms24m - 此设置指示 Java 虚拟机将其初始堆大小设置为 24 MB。通过指示 JVM 最初应分配给堆的内存数量,可以使 JVM 不必在 IDE 占用较多内存时增加堆大小。

-Xmx96m - 此设置指定 Java 虚拟机应对堆使用的最大内存数量。为此数量设置上限表示 Java 进程消耗的内存数量不得超过可用的物理内存数量。对于具有更多内存的系统可以增加此限制,96 MB 设置有助于确保 IDE 在内存量为 128MB 到 256MB 的系统上能够可靠地执行操作。注意:不要将该值设置为接近或大于系统的物理内存量,否则将在主要回收过程中导致频繁的交换操作。

-XX:PermSize=20m - 此 JVM 开关不仅功能更为强大,而且能够缩短启动时间。该设置用于调整内存"永久区域"(类保存在该区域中)的大小。因此我们向 JVM 提示它将需要的内存量。该设置消除了许多系统启动过程中的主要垃圾收集事件。SunONE Studio 或其它包含更多模块的 IDE 的用户可能希望将该数值设置得更高。
下面列出了其它一些可能对 ECLIPSE 在某些系统(不是所有系统)上的性能产生轻微或明显影响的 JVM 开关。尽管使用它们会产生一定的影响,但仍值得一试。

-XX:CompileThreshold=100 - 此开关将降低启动速度,原因是与不使用此开关相比,HotSpot 能够更快地将更多的方法编译为本地代码。其结果是提高了 IDE 运行时的性能,这是因为更多的 UI 代码将被编译而不是被解释。该值表示方法在被编译前必须被调用的次数。

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC - 如果垃圾回收频繁中断,则请尝试使用这些开关。此开关导致 JVM 对主要垃圾回收事件(如果在多处理器工作站上运行,则也适用于次要回收事件)使用不同的算法,这些算法不会影响整个垃圾回收进程。注意:目前尚不确定此收 集器是提高还是降低单处理器计算机的性能。

-XX:+UseParallelGC - 某些测试表明,至少在内存配置相当良好的单处理器系统中,使用此回收算法可以将次要垃圾回收的持续时间减半。注意,这是一个矛盾的问题,事实上此回收器主 要适用于具有千兆字节堆的多处理器。尚无可用数据表明它对主要垃圾回收的影响。注意:此回收器与 -XX:+UseConcMarkSweepGC 是互斥的。

我的机器是512MB的内存
下面是我的eclipse启动参数:eclipse.exe -vmargs -Xverify:none -Xms64M -Xmx256M -XX:PermSize=20M -XX:+UseParallelGC

-----

我的电脑是1G内存, 有一次内存不足了... MyEclipse 就推荐我使用一个启动参数, 现在我的启动参数是:


eclipse.exe -vmargs -Xverify:none -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M -XX:+UseParallelGC

Wednesday, May 27, 2009

在Eclipse中使用Gvim

更多精彩请到 http://www.139ya.com

在Eclipse中使用Gvim : http://ganzhi.blogspot.com/2007/03/vimeclipse.html

Working Directory : ${project_loc}
Arguments : ${resource_loc} 或如下设置

Refresh: The selected resource

命令参数可以这样设置:
-p --remote-tab-silent ${resource_loc}
这是打开一个新的标签页,而不是一个新的vim进程。

Friday, May 15, 2009

Eclipse 快捷键

更多精彩请到 http://www.139ya.com


编辑相关快捷键
1、〔Alt+/〕
为用户提供内容的辅助。
2、〔Ctrl+O〕
显示类中方法和属性的大纲,快速定位。
3、〔Ctrl+/〕
为光标所在行或选定行快速添加注释或取消注释。
4、〔Ctrl+M〕
窗口的最大化和还原。
5、〔Ctrl+1〕
快速修正。

查看和定位快捷键
1、〔Ctrl+K〕、〔Ctrl+Shift+K〕
快速向下和向上查找。
2、〔Ctrl+Shift+T〕
查找构建路径中的可找到类。
3、〔Ctrl+Shift+R〕
查找构建路径重点的所有文件。
4、〔Ctrl+Shift+G〕
查找类、方法和属性的引用。
5、〔Ctrl+Shift+O〕
快速生成import。
6、〔Ctrl+Shift+F〕
格式化代码。
7、〔Alt+Shift+W〕
查找当前文件所在项目中的路径。
8、〔Ctrl+L〕
定位到当前编辑器的某一行。
9、〔Alt+<-〕、〔Alt+->〕
后退历史记录和前进历史记录。
10、〔F3〕
快速定位光标位置的某个类、方法和属性。
11、〔F4〕
显示类的继承关系。

调试快捷键
1、〔Ctrl+Shift+B〕在当前行设置断点或取消断点。
2、〔F8〕继续执行,到下一个断点或程序结束。
3、〔F11〕调试最后一次执行的程序。
4、〔Ctrl+F11〕运行最后一次执行的程序。

其他
1、〔Ctrl+F6〕、〔Ctrl+Shift+F6〕:切换到下一个编辑器或上一个编辑器。
2、〔Ctrl+F7〕、〔Ctrl+Shift+F7〕:切换到下一个视图或上一个视图。
3、〔Ctrl+F8〕、〔Ctrl+Shift+F8〕:切换到下一个视角或上一个视角
ctrl + D:删除行
ctrl + M:当前窗口的最大化或最小化
ctrl + L:跳到指定的行
ctrl + 1:代码纠错提示
alt + /:代码辅助提示
F11:运行上次运行的程序
技巧:
1、如果写的代码需要抛出或者捕捉异常,在JBuilder中,你需要首先引入这个异常类,然后再在写好的代码前后加try,catch或者在方法后面加throws,在eclipse里完全不必要这样,只需要写好代码,然后按ctrl + 1,这时会出来提示,提示你是throw还是catch这个异常,选择你需要的,按下enter就可以了。
2、在写循环或者选择条件的语句时,先写出关键字如if、while,然后按alt + /自己去看有什么好处吧。接下来会出来提示代码,按下tab可以在框框中跳,按下确定跳出代码提示。

Ctrl + Shift + T: 打开类型:显示"打开类型"对话框来在编辑器中打开类型。"打开类型"选择对话框显示工作空间中存在的所有类型如类、接口等。
Ctrl + Shift + R: 打开资源:打开"打开资源"对话框以打开工作空间中的任何资源。在Package Explorer中不必浏览文件便可快速打开任意一个文件。使用这个快捷键可以打开一个对话框,在里面输入你想查找的文件或者通配符既可。
Ctrl + O: 快速大纲:打开当前所选类型的轻量级大纲图。在一个文件中直接打开一个成员变量(如字段、方法),尤其是有许多类似的方法名的时候这个快捷键将变得非常有用。
Ctrl + L: 输入行数: 转至行:打开一个对话框,允许您输入编辑器应该跳至的行号。仅适用于编辑器。输入行号,可以快速跳转到源文件中的第N行,
Ctrl + Q: 上一个编辑位置:显示上一个编辑操作的发生位置,返回到最近的修改位置。即使你查看不同的文件时,你也可以使用该快捷键来找到你最近对文件的修改位置。尤其是在文件比较大时,显得更为有用。
Ctrl + T: 快速类型层次结构:打开当前选择的类型的轻量级层次结构查看器,可以实现快速转到一个supertype或者subtype.
Ctrl + E: 快速跳转到另外一个编辑器。注意Ctrl + F6也可以实现这个功能,在使用的时候可以注意一下他们的异同。
Ctrl + ./Ctrl +,: 在一个文件中快速定位到一个问题(如错误、警告等)
Alt +← and Alt + →: 来回跳转至你所查阅的文件
F3: 快速转到一个类型声明。同时也可以按住ctrl健并点击该超链接变量或者类或者你想查看的任何声明都可以。