This paper analyzes the the multithreaded programs achieve Eclipse, discusses the application of multi-threaded approach to the development of the Eclipse client program and to pay attention to the problem, and also discussed some debugging multithreaded programs and problem solving methods.
Eclipse as a development platform, the use of more and more widespread, more and more based on the client program developed by the Eclipse Rich Client Platform. In today's increasingly complex environment, the client program is inevitable to simultaneous multi-task processing. An excellent client program will allow the user to start multiple tasks at the same time, thus greatly improving user productivity and user experience. In this paper, we talk about the Eclipse multi-task.
Eclipse-based Java programs, we have a variety of ways to achieve multi-tasking. Familiar with Java friends immediately think of the Java Thread class, which is the use of Java in one of the largest multi-task class. Eclipse platform for multi-tasking provides its own API, Job and UIJob. Job Eclipse is a Java Thread package provides a more convenient interface for us to achieve multi-tasking. The following is the basic usage of the Job:
List Job usage example
Job job = new Job ("Job Name") {
protected IStatus run (IProgressMonitor monitor) {
/ / Add your task code
return the Status.OK_STATUS;
}
};
job.schedule (1133) ;/ / delaytime
job.setUser (true) ;/ / if true show UI
job.setPriority (priority)
We will also frequently used in Eclipse Display.asynchExec (), and Display.synchExec () to start the execution of tasks. These two methods in order to help us complete the task of the interface operation. The following is the usage of Display.asynchExec (), the Display.synchExec () and similar.
In Listing 2 Display.synchExec () usage examples
Display.getDefault (). AsyncExec (new Runnable () {
public void run () {
/ / Add your task code
}
});
Typically, the best in Eclipse Eclipse Job interface to multi-task, rather than using the Java Thread. Why? There are several reasons:
Job is a reusable unit of work, a job we can easily perform it repeatedly. Job provides a convenient interface, so that we in the process can be very convenient communication with the outside world, to report the progress in the implementation of Eclipse provides the mechanism so that programmers can easily intervene Job scheduling, for example, we can easily achieve each only one of the same type Job running Eclipse default Job management procedures can view all current job and their progress, but also provides UI termination, pause, continue to specify the job using the Job can improve the performance of the program, saving thread creation and destruction overhead. Eclipse Job encapsulates the implementation of the thread pool. When we start a Job, Eclipse will not immediately create a new Thread, it will look for idle thread in the thread pool, if there is an idle thread, it will directly run idle threads Your Job. A job is terminated, it corresponds to the thread will not terminate immediately, it will be returned to the thread pool for reuse. In this way, we can save the overhead of creating and destroying threads several ways to discuss issues of implementation and use of Eclipse Job.
Implementation of the Eclipse Job
The Eclipse core package provides a JobManager class, which implements the IJobManager interface Eclipse Job Management and Scheduling JobManager. The JobManager maintains a thread pool used to run the job. When we call the Job schedule Job JobManager first into a job running waiting for the queue. The JobManager notice new Job to run the waiting queue thread pool. The thread pool will find an idle thread to run the job, if there is no idle thread, the thread pool creates a new thread to run the Job. Once the job has finished running, running Job thread returns to the thread pool for the next use. Job to run the process from the above, we can see that The JobManager involved in the whole process of running a Job, it understands Job when to start, when the end of each time job running state. The JobManager the running of these Job in order to interface to the user, but it also provides the interface so that we can intervene Job scheduling, so that we have a more powerful ability to control Job.
More convenient for us to understand the state of the job which the JobManager set Job a state flag, we can getState method in Job Job current state value in order to understand its status:
NONE: When a job just constructed, the job will be in this state. When a job is completed (including), the job's status changes back to this state. WAITING: When we call job shedule, the JobManager the Job into the job queue waiting to run, then Job status for waiting. RUNNING: When a job begins execution, the job of the state becomes RUNNING. SLEEPING: When we call Job's sleep, Job will turn this state. When we call schudule method to bring the delay parameters, the job of the state will be transferred to this state, in this period of delay waiting time job in this state. This is a sleep state, Job in this state can not be immediately transferred to the run. We can call the the Job's wakeup method to Job wake. In this way, Job will be transferred to the WAITING state waiting to run.
Eclipse UI thread
In addition, the Eclipse thread processing, the concept of a UI thread. The Eclipse program's main thread is a special thread, after the start of the program will be executed this thread, is the main () function where the thread. As a desktop application, our main thread is mainly responsible for the response of the interface as well as draw interface elements, so usually we call it the UI thread.
The following code, readers will be very familiar with the compiled SWT applications. It generally appears at the end of the main function. Let closer look at its details.
/ / When the window is not released
while (! shell.isDisposed ()) {
/ / If the display object event queue without waiting for an event, let the thread into a wait state
if (! display.readAndDispatch ())
display.sleep ();
}
The above procedure is actually our UI thread processing logic: When the program starts, the UI thread reads the event queue, there is no event pending. If so, it will be dealt with accordingly, if not it will go to sleep. If the arrival of a new event, it will be awakened, for processing. Need to be addressed by the UI thread events include a drawing event in the user's mouse and keyboard operation event, the operating system or program. In general, the process of handling the event is in response to a user operation process.
A good desktop application needs to immediately react to the user's actions, which means that our UI thread must deal with a variety of events as soon as possible. In the UI thread from the point of view of our program, we can not be a large number of calculations or wait, or user action events, lack of timely treatment. Typically, if a large number of calculations or take a long time to wait (for example, network operation or database operations), we must be long program alone open up a thread to execute. Although this program running in the background, but does not affect the operation interface.
The main threads, all the threads are non-UI thread. Eclipse program, all the operation of the interface elements must be on the UI thread to execute, otherwise it will throw an Exception, so we have to distinguish between the UI thread and non-UI thread, UI operations on the UI thread to perform.
How to determine whether the current thread UI thread: You can by calling Display.getCurrent () to know whether the current thread is the UI thread. If Display.getCurrent () returns null, which means that the current is not the UI thread.
Eclipse thread of typical situations
Control the Job run concurrently for some job, in order to avoid concurrency problems, we hope at the same time only one such job in the running, we need to control the job run concurrently. In another case, we also need to control the concurrent operation of the Job: in the program for a task, we may start a job to perform, it is feasible for a small number of tasks, but if we predict may also have a lot of tasks, each task to start a Job, we start at the same time the job will be very much. Job occupation of a large number of resources, affect the execution of other tasks. Job rule we can use to control the concurrent execution of Job. Simple we can use the following code. We first define one follows the rule:
private ISchedulingRule Schedule_RULE = new ISchedulingRule () {
public boolean contains (ISchedulingRule rule) {
to return this.equals (rule);
}
public boolean isConflicting (ISchedulingRule rule) {
to return this.equals (rule);
}
};
Need to avoid running at the same time job, we can set up their rule into the Rule defined above. Such as:
myjob1.setRule (Schedule_RULE);
myjob2.setRule (Schedule_RULE);
This two Job myjob1 and myjob2, they do not run concurrently. Myjob2 waits the myjob1 After execution. This is provided by the Eclipse JobManager to achieve. The JobManager can guarantee all start the job, any two Job rule there is no conflict. The rule we defined above is the most simple. We can rewrite isConflicting functions to achieve some of the more complex control, such as control at the same time the same type of Job only up to the specified number in the running. But we should pay attention to, the isConflicting can not be too complex. Once a Job rule conflicts with other Job rule, isConflicting method is called many times. If the calculation is too complex, and will affect the overall performance.
Based on the need to perform the job we have job may not be executed immediately, in some cases, until the job ready to perform when the tasks to be performed by the Job has no meaning. At this point, we can use the Job the shouldSchedule (), and shouldRun () to avoid the operation of the Job. We define a Job, we can override shouldSchedule and shouldRun. In these methods, we can check the Job run some prerequisites If these conditions are not met, we can return false. The JobManager arrangements Job run, it will first call the Job shouldSchedule method and if returns false, JobManager not arrange this Job run. Similarly, the JobManager before the real start a thread to run a Job, it is called the Job shouldRun method returns false, it is no longer running this job. In the following example, we want to start a Job After ten seconds to update the contents of the text box. In order to ensure our Job runtime is meaningful, we need to ensure that we want to update the text box has not been destroyed, overloaded shouldSchedule shouldRun methods.
Text text = new Text (parent, SWT.NONE);
UIJob refreshJob = new UIJob ("update interface") {
public IStatus runInUIThread (IProgressMonitor monitor) {
text.setText ("text");
return the Status.OK_STATUS;
}
public boolean shouldSchedule () {
the return! text.isDisposed ();
}
the public boolean shouldRun () {
the return! text.isDisposed ();
}
};
refreshJob.schedule (10000);
Long-processing tasks involved in the UI thread we often encounter such a situation: User Action menu or button triggers a query large amounts of data, after the data query updates the table and other interface elements. The handler is generally triggered by the user clicks on the menu or button in the UI thread, in order to avoid blocking the UI, we have the data query time-consuming work into separate Job Once the data query, we must update the interface, then we need to use the UI thread for processing. Here is the sample code to handle this situation:
button.addSelectionListener (new SelectionListener () {
public void widgetSelected (SelectionEvent e) {
the perform ();
}
public void widgetDefaultSelected (SelectionEvent e) {
the perform ();
}
private void perform () {
Job job = new Job ("Get Data") {
protected IStatus run (IProgressMonitor monitor) {
/ / Add code to get data
Display.getDefault (). AsyncExec (new Runnable () {
public void run () {
/ / Add the updated interface code
}
});
}
};
job.schedule ();
}
});
Delay the implementation of Job, we often need to refresh some of our interface elements according to the selected object to avoid useless job running. If we continuously and quickly change the selection, and each refresh the interface area involved is relatively large, the interface will appear flashing. From the user's point of view, we quickly change the selection, want to see only the last selected results of the middle of the screen refresh is unnecessary.
In in Jface StructuredViewer provides the addPostSelectionChangedListener method. If we use this method to listen for the SelectionChanged event, when the user is holding down arrow keys to change the selected, we will only receive a SelectionChanged event. So that we can avoid over-refresh interface.
Fact Jface is to delay the implementation of the Job to achieve this functionality. We can implement similar functionality:
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 (Update Interface) {
protected IStatus runInUIThread (IProgressMonitor monitor) {
/ / Update interface
return the Status.OK_STATUS;
}
public boolean belongsTo (Object family) {
return family == UPDATE_UI_JOBFAMILY;
}
The}. Schedule (500);
}
});
First of all, we need to interface to update the code into a UIJob Job execution delay of 500 milliseconds (we may need to change the delay time). SelectionChanged event soon to come, we call Job.getJobManager (). Cancel (UPDATE_UI_JOBFAMILY) not previously run job cancel, so that only the last Job will actually run.
Sometimes, we need to wait for the UI thread in a non-UI thread to finish executing, we can continue to perform in the UI thread waiting for the end of the non-UI thread. For example, we want to display in the UI thread some data, but these data need to be obtained from the database or remote network. So, we will start a non-UI thread to acquire the data. The UI thread must wait for the non-UI thread execution is complete, we can continue to perform. Of course, a simple method is to use its join. Non-UI thread join method can be called in the UI thread, so that we can wait for it to perform over us to carry on. However, this will be a problem. When the UI thread is waiting, means that we no longer respond to interface operation, it will not refresh. In this way, the user will feel our program as dead as there is no reaction. At this time, we can use the Class ModalContext. You can put your task to be performed to obtain data the run method ModalContext to run (see below). ModalContext Your task will be placed in an independent non-UI thread, and wait for it to completely before proceeding. Join method is the ModalContext not stop UI event processing while waiting. So that our program would not be without response.
try {
ModalContext.run (new IRunnableWithProgress () {
public void run (IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
/ * Code that need to be performed in a non-UI thread * /
ModalContext.checkCanceled (monitor);
}
}, True, new NullProgressMonitor (), Display.getCurrent ());
} Catch (InvocationTargetException e) {
} Catch (InterruptedException e) {
}
Sometimes, we need the associated Job processing for the associated Job unified processing. Such as the need to cancel these Job, or wait for the end of all of these Job. At this time, we can use the Job family. For associated with the job, we can set them with a Job Family. We need to override the the belongsTo method of Job to set a Job Job Family.
Private Object MY_JOB_FAMILY = new Object ();
Job job = new Job ("Job Name") {
protected IStatus run (IProgressMonitor monitor) {
/ / Add your task code
return the Status.OK_STATUS;
}
public boolean belongsTo (Object family) {
. return MY_JOB_FAMILY.equals (family);
}
};
JobManager a number of ways we can use to operate for Job Family:
Job.getJobManager (). Cancel (MY_JOB_FAMILY); / / to cancel all belonging to the MY_JOB_FAMILY all Job
The all Job Job.getJobManager (). Join (MY_JOB_FAMILY); / / wait MY_JOB_FAMILY the end of
Job.getJobManager (). Sleep (MY_JOB_FAMILY); / / will all belonging to MY_JOB_FAMILY Job into sleep mode
Job.getJobManager (). Wakeup (MY_JOB_FAMILY); / / will all belonging to MY_JOB_FAMILY Job wake
The thread deadlock debugging and solving skills
Once we thread our program it is possible deadlocks. The event of a deadlock, deadlock thread does not respond, resulting in our application performance degradation. If our UI thread deadlock, our program will not respond to, it is necessary to restart the program. Found a deadlock situation in the development of our multi-threaded program to solve the deadlock problem is extremely important to improve the stability and performance of our program.
If we find that the program is running exceptions (for example, the program is not responding), we must first determine whether there has been a deadlock. By following these steps, we can determine whether a deadlock deadlock thread:
Response test cases in Eclipse Debug mode to run the program execution reproduce the problem in the Eclipse Debug View, select the main thread (Thread [main]), select the menu Run-> Suspend. At this time, Eclipse will expand the function call stack of the main thread, we can see the current main thread of the operation being performed. Typically, Eclipse and wait for the function call stack will be similar to the following:
Image example
If the main line process occurs deadlock, the top level of the call stack will generally be your own function call, you can look at your current function call to determine the main thread waiting for something to use the same method to view other threads, especially those who wait UI thread thread We need to find out the current thread to wait between each other, in order to find out the reason for the deadlock. You can find out deadlock thread processing for different situations:
Reduce the lock granularity to increase concurrency order to adjust the resource request will need to wait for resources tasks into separate thread
Job should pay attention to the problem
Do not use Job Thread.sleep method. If you want the Job to sleep best job sleep. Although, use Thread.sleep and sleep in Job achieve the effect is almost, but the way they are implemented completely different impact on the system are not the same. We know that the Eclipse Job is managed by the Eclipse JobManager. If we call the job sleep method, the JobManager the job into sleep state, its corresponding thread will be back into the thread pool waiting to run other Job. And if we are in the Job directly call Thread.sleep method, it will direct the thread running Job to sleep, other job, it is impossible to reuse this thread. The same time, run the Job thread goes to sleep, job status or Running (running), we do not Job's wakeup method can be used to wake the Job Job Cancel. We will generally intuitive, call the cancel method of Job, Job will stop running. In fact, this is not necessarily true when the job in a different state, we call the cancel method of Job from the effect is different. Job in WAITING status and SLEEPING state, once we call the cancel method, the JobManager the job directly removed from the queue waiting to be run, the job will not run again, then the cancel method will return true. However, if the job is running, the cancel method call does not immediately terminate the operation of Job, it will only set a flag to indicate that the job has been canceled. We can use the Job run method argument passed IProgressMonitor monitor, this parameter isCanceled method will return Job status is canceled. If necessary, we must check the appropriate place in our code sign of Job is canceled respond appropriately. In addition, due to the call of Job's cancel method does not necessarily immediate termination of Job, Job run if we need to wait to be canceled again and again perform, we can use the following code: if (! Job.cancel ())
job.join ();
Join method. Join method will lead to a thread wait for another thread, once the waiting thread has a waiting thread lock, it will produce a deadlock. When the need to synchronize our thread, this deadlock situation is very prone, so be very careful when we use the join, as far as possible alternative to other methods. To avoid the errors caused by outdated job. As we start the thread is not necessarily performed immediately, when our Job starts running, the situation may occur changes. Job processing code to take into account these situations. A typical case is that we start, we will start a dialog box or initialize a ViewPart the job to complete the data read, once the data reading is finished, we will start the new UI Job update the UI . Sometimes, a user in the Open dialog box or View, immediately close the dialog box or View. At this time we start the thread has not been interrupted, Once you go to update the UI in the Job, an error occurs. In our code must be dealt with accordingly. So, before we update interface elements in the thread, we must first check whether the corresponding controls dispose Conclusion
Eclipse-based client-side development, the use of multi-threading can greatly our program concurrent processing, at the same time have a good help to improve the user experience. Multithreaded programs, however, also has its negative side, we do not abuse the thread:
First of all, the multi-threaded program will greatly increase the complexity of our procedures, our development and debugging more difficult Secondly, too many threads, is apt to cause deadlock, data synchronization and other concurrent problems occur In addition, since the thread creation and destruction overhead , the overall performance of the program may be lowered because of the use of too many threads Therefore, we must be cautious in the use of threads. This article the Eclipse discussion thread, I hope you can use the thread to be helpful. The actual situation is more complicated, the method mentioned in the article are for reference only, the reader for different practical problems need to be specific analysis, in order to identify the best solution.
|