In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Editor to share with you how to use multithreading in Eclipse client programs. I hope you will get something after reading this article. Let's discuss it together.
As a development platform, Eclipse is more and more widely used, and more and more client programs are developed based on Eclipse Rich Client Platform. In today's increasingly complex application environment, our client programs inevitably have to multitask at the same time. An excellent client program will allow users to start multiple tasks at the same time, thus greatly improving the user's productivity and user experience. In this article, let's talk about how to implement multitasking in Eclipse.
In our Eclipse-based Java program, we have many ways to provide multitasking. Friends who are familiar with Java will immediately think of Java's Thread class, which is the most frequently used multitasking class in Java. The Eclipse platform provides its own API for multitasking, which is Job and UIJob. Job in Eclipse is an encapsulation of Java Thread, which provides a more convenient interface for us to realize multitasking. The following is the basic usage of Job:
Listing 1. Job usage example
Job job = new Job ("Job Name") {protected IStatus run (IProgressMonitor monitor) {/ / add your task code return Status.OK_STATUS;}} here; job.schedule (delayTime)
In Eclipse, we also often use Display.asynchExec () and Display.synchExec () to start task execution. These two methods are mainly to facilitate us to complete the task of interface operation. The following is the use of Display.asynchExec (), which is similar to Display.synchExec ().
Listing 2. Example of Display.synchExec () usage
Display.getDefault () .asyncExec (new Runnable () {public void run () {/ / add your task code here}})
In general, in Eclipse, it is best to use the Job interface provided by Eclipse for multitasking, rather than using Java's thread. Why? There are mainly the following reasons:
Job is a reusable unit of work, and a Job can be easily executed multiple times.
Job provides a convenient interface, which makes it very convenient for us to communicate with the outside world and report the current progress of implementation.
Eclipse provides a mechanism for programmers to easily intervene in the scheduling of Job. For example, we can easily implement that there is only one Job of the same type running at a time.
Eclipse provides Job management programs by default, which can view all current Job and their progress, and also provide UI termination, pause, and resume specified Job.
Using Job can improve the performance of the program and save the overhead of thread creation and destruction. Job in Eclipse encapsulates the implementation of thread pool. When we start a Job, Eclipse will not immediately create a new Thread, it will look in its thread pool to see if there are free threads, if there are free threads, it will directly run your Job with free threads. When a Job terminates, its corresponding thread does not immediately terminate, it is returned to the thread pool for reuse. In this way, we can save the overhead of creating and destroying threads
Let's discuss the implementation and use of Job in Eclipse from several aspects.
Implementation of Job in Eclipse
A JobManager class is provided in the core package of Eclipse, which implements the IJobManager interface, and the management and scheduling of Job in Eclipse are implemented by JobManager. JobManager maintenance has a thread pool for running Job. When we call the schedule method of Job, the Job is first put into a waiting queue running by Job by JobManager. After that, JobManager notifies the thread pool that a new Job has joined the run wait queue. The thread pool will find an idle thread to run Job, and if there is no idle thread, the thread pool will create a new thread to run Job. Once the Job is finished, the thread running Job returns to the thread pool for next use. From the process of running Job above, we can see that JobManager is involved in the whole process of running Job. It knows when Job starts, when it ends, and the running status of Job every time. JobManager provides the information about the operation of Job to users in the way of interface, and it also provides an interface for us to intervene in the scheduling of Job, etc., so that we have a stronger ability to control Job.
In order to make it easier for us to understand the state of Job, JobManager sets a status flag bit of Job. We can obtain the current state value of Job through the getState method of Job to understand its status:
NONE: when a Job is first constructed, the Job is in this state. When a Job is finished (including being canceled), the state of the Job changes back to this state.
WAITING: when we call the shedule method of Job, JobManager puts Job in the Job queue waiting to run, and the status of Job is WAITING.
RUNNING: when a Job starts to execute, the state of the Job changes to RUNNING.
SLEEPING: when we call the sleep method of Job, Job changes to this state. When we call the schudule method with a delay parameter, the state of the Job is also transferred to this state, and the Job is in this state for the period of delay waiting. This is a sleep state in which Job cannot immediately turn into operation. We can call the wakeup method of Job to wake up Job. In this way, Job will go into the WAITING state and wait for it to run.
UI thread in Eclipse
In addition, in Eclipse threading, there is a concept of UI threads. The main thread in the Eclipse program is a special thread, which will be executed first after the program starts, that is, the thread in which our main () function is located. As a desktop application, our main thread is mainly responsible for responding to the interface and drawing interface elements, so we usually call it UI thread.
The following code will be familiar to readers who have written SWT applications. It usually appears at the end of the main function. Let's take a closer look at its details.
/ / while (! shell.isDisposed ()) {/ / if there are no waiting events in the display object event queue when the window is not released, put the thread into the waiting state if (! display.readAndDispatch ()) display.sleep ();}
The above program is actually the processing logic of our UI thread: when the program starts, the UI thread reads the event waiting queue to see if there are any events waiting to be handled. If there is, it will deal with it accordingly, and if not, it will go to sleep. If a new event comes, it will be awakened and dealt with. The events that the UI thread needs to handle include the user's mouse and keyboard operation events, and drawing events emitted in the operating system or program. Generally speaking, the process of handling events is the process of responding to user actions.
A good desktop application needs to respond as quickly as possible to the user's actions, which means that our UI thread must handle various events as soon as possible. From the point of view of our program, we can't do a lot of computation or wait in the UI thread, otherwise the user action events will not be handled in time. In general, if there are a large number of calculations or need to wait for a long time (such as network operations or database operations), we must open up a separate thread to execute these long-time programs. In this way, although the program is running in the background, it will not affect the operation on the interface.
All threads except the main thread are non-UI threads. In the Eclipse program, all our operations on the interface elements must be performed in the UI thread, otherwise Exception will be thrown, so we have to distinguish between the UI thread and the non-UI thread to ensure that our operations on the UI are performed in the UI thread.
How to determine whether the current thread is a UI thread: you can know whether the current thread is a UI thread by calling Display.getCurrent (). If Display.getCurrent () returns empty, it means that it is not currently a UI thread.
Several typical situations of using threads in Eclipse
Control the concurrent operation of Job
For some Job, in order to avoid concurrency problems, we want to have only one such Job running at a time, and we need to control the concurrency of Job. In another case, we also need to control the concurrent running of Job: for a task in our program, we may start a Job to execute, for a small number of tasks, this is feasible, but if we predict that there may be a large number of tasks at the same time, if each task starts a Job, we will start a lot of Job at the same time. These Job will encroach on a lot of resources and affect the execution of other tasks. We can use Job's rule to control the concurrent execution of Job. The simple one can be achieved through the following code. Let's first define a rule as follows:
Private ISchedulingRule Schedule_RULE = new ISchedulingRule () {public boolean contains (ISchedulingRule rule) {return this.equals (rule);} public boolean isConflicting (ISchedulingRule rule) {return this.equals (rule);}}
For Job that needs to avoid running concurrently, we can set their rule to the rule defined above. Such as:
Myjob1.setRule (Schedule_RULE); myjob2.setRule (Schedule_RULE)
In this way, the two Job, myjob1 and myjob2, will no longer be executed at the same time. Myjob2 waits for myjob1 to finish executing. This is provided by Eclipse's JobManager. JobManager can guarantee that there is no conflict between the rule of any two Job in all launched Job. The rule we defined above is the simplest. We can rewrite the isConflicting function to implement some more complex controls, such as controlling that only a specified number of Job of the same type are running at the same time. However, we should note that the isConflicting method should not be too complex. Once the rule of one Job conflicts with the rule of another Job, the isConflicting method is called many times. If the calculation is too complex, it will affect the overall performance.
Execute Job as needed
Because some of our Job may not be executed immediately, in some cases, by the time the Job is ready for execution, the task that the Job is going to perform is meaningless. At this point, we can use Job's shouldSchedule () and shouldRun () to avoid running Job. When we define a Job, we can overload the shouldSchedule and shouldRun methods. In these methods, we can check some of the prerequisites for Job to run, and if these conditions are not met, we can return false. When JobManager arranges the Job to run, it will first call the shouldSchedule method of the Job, and if it returns false,JobManager, it will no longer schedule the Job to run. Similarly, before JobManager actually starts a thread to run a Job, it calls the shouldRun method of the Job, and if false is returned, it no longer runs the Job. In the following example, we want to start a Job to update the contents of the text box after ten seconds. To ensure that our Job runtime is meaningful, we need to make sure that the text box we want to update is not destroyed, and we overload the shouldSchedule and shouldRun methods.
Text text = new Text (parent,SWT.NONE); UIJob refreshJob = new UIJob ("update interface") {public IStatus runInUIThread (IProgressMonitor monitor) {text.setText ("new text"); return Status.OK_STATUS;} public boolean shouldSchedule () {return! text.isDisposed ();} public boolean shouldRun () {return! text.isDisposed ();}; refreshJob.schedule (10000)
Tasks that involve long-time processing in UI threads
We often encounter such a situation: users operating menus or buttons will trigger the query of a large amount of data, and update interface elements such as tables after the data query. The processing program triggered by the user clicking on the menu or button is usually in the UI thread. In order to avoid blocking the UI, we must put the time-consuming work such as data query into a separate Job. Once the data query is finished, we have to update the interface, and then we need to use UI thread for processing. Here is the sample code to handle this situation:
Button.addSelectionListener (new SelectionListener () {public void widgetSelected (SelectionEvent e) {perform ();} public void widgetDefaultSelected (SelectionEvent e) {perform ();} private void perform () {Job job = new Job ("get data") {protected IStatus run (IProgressMonitor monitor) {/ / add the code to get the data here Display.getDefault (). AsyncExec (new Runnable () {public void run () {/ / add the code to update the interface}});}; job.schedule ();}})
Delay the execution of Job to avoid useless Job operation
We often need to refresh some of our interface elements based on the selected objects. If we change the selection continuously and quickly, and the area involved in each refresh of the interface is relatively large, the interface will flash. From the user's point of view, we quickly change the choice, want to see only the final selected results, the interface refresh in the middle is unnecessary.
In Jface, StructuredViewer provides the addPostSelectionChangedListener method. If we use this method to listen for selectionChanged events, we will receive only one selectionChanged event when the user keeps pressing the arrow key to change the selection. In this way, we can avoid excessive refresh of the interface.
In fact, this function is achieved in Jface by delaying the execution of Job. We can also implement similar functions ourselves:
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 Status.OK_STATUS;} public boolean belongsTo (Object family) {return family== UPDATE_UI_JOBFAMILY;}} .schedule;}})
First, we need to put the code for the interface update into a UIJob, and we delay the execution of the Job by 500ms (we can change the delay as needed). If the next selectionChanged event arrives soon, our call Job.getJobManager (). Cancel (UPDATE_UI_JOBFAMILY) cancels the previously unrun Job so that only the last Job will actually run.
Waiting for the end of a non-UI thread in a UI thread
Sometimes we need to wait for a non-UI thread to finish execution in the UI thread before we can continue execution. For example, we want to display some data in a UI thread, but the data needs to be obtained from a database or a remote network. Therefore, we will start a non-UI thread to get the data. Our UI thread must wait for the non-UI thread to finish before we can continue execution. Of course, a simple way to do this is to use join. We can call the join method of the non-UI thread in the UI thread so that we can wait for it to finish executing before we continue. However, there will be a problem. When our UI thread waits, it means that our program will no longer respond to interface operations or refresh. In this way, users will feel that our program is as unresponsive as dead. At this point, we can use the ModalContext class. You can use ModalContext's run method to run the tasks you want to perform to get the data (as follows). ModalContext will put your task into a separate non-UI thread and wait for it to finish before continuing. Unlike the join method, ModalContext does not stop the processing of the UI event while waiting. So that our program will not be unresponsive.
Try {ModalContext.run (new IRunnableWithProgress () {public void run (IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {/ * Code to be executed in a non-UI thread * / ModalContext.checkCanceled (monitor);}, true, new NullProgressMonitor (), Display.getCurrent ();} catch (InvocationTargetException e) {} catch (InterruptedException e) {}
Unified processing for the associated Job
Sometimes we need to deal with the associated Job together. For example, you need to cancel these Job at the same time, or wait for all of these Job to end. At this point we can use Job Family. For the associated Job, we can set them to the same Job Family. We need to overload the belongsTo method of Job to set a Job Family of Job.
Private Object MY_JOB_FAMILY = new Object (); Job job = new Job ("Job Name") {protected IStatus run (IProgressMonitor monitor) {/ / add your task code here return Status.OK_STATUS;} public boolean belongsTo (Object family) {return MY_JOB_FAMILY.equals (family);}}
We can use a series of methods of JobManager to operate on Job Family:
Job.getJobManager () .cancel (MY_JOB_FAMILY); / / cancel all JobJob.getJobManager () .join (MY_JOB_FAMILY) belonging to MY_JOB_FAMILY; / / wait for all Job belonging to MY_JOB_FAMILY to end Job.getJobManager () .sleep (MY_JOB_FAMILY); / / transfer all Job belonging to MY_JOB_FAMILY to sleep state Job.getJobManager () .wakeup (MY_JOB_FAMILY) / / Wake up all Job belonging to MY_JOB_FAMILY
Debugging and solving skills of thread deadlock
Once we use threads, there may be deadlocks in our program. Once a deadlock occurs, our deadlocked thread will not respond, resulting in a decline in the performance of our program. If our UI thread has a deadlock, our program will not respond and must restart the program. Therefore, in our multithreaded program development, it is very important to find deadlock and solve the deadlock problem to improve the stability and performance of our program.
If we find that the program is running abnormally (for example, the program is not responding), we first need to determine whether a deadlock has occurred. We can determine whether there is a deadlock and a deadlocked thread by following these steps:
Run the program in Debug mode in Eclipse
The problem of test case reproduction for executing responses
Select the main thread (Thread [main]) in the Debug View of Eclipse, and select menu Run- > Suspend. At this point, Eclipse expands the function call stack of the main thread, and we can see what the main thread is doing.
Typically, Eclipse is waiting for a user's action, and its function call stack looks similar to the following:
Picture example
If the main thread has a deadlock, the top layer of the function call stack will usually be your own function call. You can check your current function call to determine what the main thread is waiting for.
Use the same method to look at other threads, especially those waiting for UI threads
We need to find out the waiting relationship between the current threads in order to find out the cause of the deadlock. After we find out the thread of the deadlock, we can deal with it for different situations:
Reduce the granularity of locks and increase concurrency
Adjust the order of resource requests
Put tasks that need to wait for resources to be executed in a separate thread
Problems needing attention in the use of Job
Do not use the Thread.sleep method in Job. If you want to put Job to sleep, you'd better use Job's sleep method. Although the sleep methods using Thread.sleep and Job achieve similar results, they are implemented in completely different ways and have different effects on the system. We know that Job in Eclipse is managed by Eclipse's JobManager. If we call the sleep method of Job, JobManager will put the Job to sleep, and its corresponding thread will be put back into the thread pool waiting to run other Job. If we call the Thread.sleep method directly in Job, it will directly put the thread running Job to sleep, making it impossible for other Job to reuse the thread. At the same time, although the thread running the Job is asleep, the state of the Job is still Running (running state), and we cannot wake up the Job with the wakeup method of Job
Cancellation of Job. It is generally intuitive to assume that once the cancel method of Job is called, Job will stop running. In fact, this is not necessarily true. When Job is in a different state, the effect of calling Job's cancel method is different. When Job is in WAITING state and SLEEPING state, once we call the cancel method, JobManager will directly remove Job from the queue waiting to run, Job will no longer run, and the cancel method will return true. But if Job is running, the cancel method call does not immediately terminate the Job, it just sets a flag indicating that the Job has been cancelled. We can use the parameter IProgressMonitor monitor passed in by the run method of Job, and the isCanceled method of this parameter returns the status of whether the Job has been cancelled. If necessary, we must check the flag whether the Job has been cancelled in the appropriate place in our code and respond appropriately. In addition, since calling the cancel method of Job does not necessarily terminate Job immediately, if we need to wait for the cancelled Job to finish running before executing, we can use the following code:
If (! job.cancel () job.join ()
The use of Join method. Because the join method causes one thread to wait for another thread, a deadlock occurs once the waiting thread has a lock needed by the waiting thread. This kind of deadlock is very easy to occur when synchronization is needed in our threads, so we have to be very careful when using join and try to replace it in other ways.
Avoid errors caused by outdated Job. Since the thread we started is not necessarily executed immediately, things may have changed when our Job started running. We should take these situations into account in the processing code of Job. A typical situation is that when we start a dialog box or initialize a ViewPart, we start some Job to complete some data reading, and once the data reading is finished, we will start a new UI Job to update the corresponding UI. Sometimes, the user closes the dialog box or View as soon as they open it. At this point, the thread we started is not interrupted, and once we update the UI in Job, there will be an error. It must be dealt with accordingly in our code. So, before we update the interface element in the thread, we must first check whether the corresponding control has been dispose.
After reading this article, I believe you have a certain understanding of "how to use multithreading in Eclipse client programs". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for reading!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.