- Java 9 Programming Blueprints
- Jason Lee
- 790字
- 2021-07-02 18:56:30
Updating the process list
If the application started and showed a list of processes, but never updated that list, it wouldn't be very useful at all. What we then need is a way to update the list periodically, and for that, we'll use a Thread.
As you may or may not know, a Thread is roughly a means to run a task in the background (the Javadoc describes it as a thread of execution in a program). A system can be single or multithreaded, depending on the needs and runtime environment of the system. And multithreaded programming is hard to get right. Luckily, our use case here is fairly simple, but we must still exercise caution, or we'll see some really unexpected behavior.
Ordinarily, the advice you would get when creating a Thread is to implement a Runnable interface, which you will then pass to the thread's constructor, and that's very good advice, as it makes your class hierarchy much more flexible, since you're not tied to a concrete base class (Runnable is an interface). In our case, however, we have a relatively simple system that has little to gain from that approach, so we'll extend Thread directly and simplify our code a little as well as encapsulating our desired behavior. Let's take a look at our new class:
private class ProcessListUpdater extends Thread { private volatile boolean running = true; public ProcessListRunnable() { super(); setDaemon(true); } public void shutdown() { running = false; } @Override public void run() { while (running) { updateList(); try { Thread.sleep(5000); } catch (InterruptedException e) { // Ignored } } } public synchronized void updateList() { processList.setAll(ProcessHandle.allProcesses() .collect(Collectors.toList())); processView.sort(); } }
We have a pretty basic class, which we've given a reasonable and meaningful name that extends Thread. In the constructor, note that we call setDaemon(true). This will allow our application to exit as expected and not block, waiting for the thread to terminate. We've also defined a shutdown() method, which we'll use from our application to stop the thread.
Finally, we have the heart of our Thread class, run(), which loops infinitely (or until running becomes false), sleeping for five seconds after performing its work. The actual work is done in updateList(), which builds the list of processes, updates ObservableList we discussed earlier, and then instructs TableView to re-sort itself, based on the user's sort selection, if any. This is a public method, allowing us to call this at need, as we did in killProcessHandler(). That leaves us with the following block of code to set it up:
@Override public void initialize(URL url, ResourceBundle rb) { processListUpdater = new ProcessListUpdater(); processListUpdater.start(); // ... }
The following code will shut it down, which we've already seen in closeHandler():
processListUpdater.shutdown();
The eagle-eyed will notice that updateList() has the synchronized keyword on it. This is to prevent any sort of race condition that might be caused by calling this method from multiple threads. Imagine the scenario where the user decides to kill a process and clicks on OK on the confirmation dialog at the exact moment the thread wakes up (this type of thing happens more often than you might think). We could conceivably have two threads calling updateList() at the same time, resulting in the first thread hitting processView.sort() just as the second is hitting processList.setAll(). What happens when sort() is called while another thread is rebuilding the list? It's hard to say for sure, but it could be catastrophic, so we want to disallow that. The synchronized keyword instructs the JVM to allow only one thread to execute the method at a time, causing all others to queue up, waiting their turn (note that their execution order is non-deterministic, so you can't base any expectations on the order in which threads get to run a synchronized method). This avoids the potential for a race condition, and ensures that our program doesn't crash.
While appropriate here, care must be taken with synchronized methods, as acquiring and releasing the locks can be expensive (though much less so with modern JVMs) and, more importantly, it forces threads to run sequentially when they hit this method call, which can cause a very undesirable lag in the application, especially in GUI applications. Keep that in mind when writing your own multithreaded applications.
- ExtGWT Rich Internet Application Cookbook
- 深度實踐OpenStack:基于Python的OpenStack組件開發(fā)
- 人人都是網(wǎng)站分析師:從分析師的視角理解網(wǎng)站和解讀數(shù)據(jù)
- Java項目實戰(zhàn)精編
- Java Web程序設(shè)計任務教程
- Java面向?qū)ο蟪绦蛟O(shè)計
- ArcGIS for Desktop Cookbook
- HoloLens與混合現(xiàn)實開發(fā)
- Spring MVC+MyBatis開發(fā)從入門到項目實踐(超值版)
- Illustrator CS6設(shè)計與應用任務教程
- 新印象:解構(gòu)UI界面設(shè)計
- 單片機原理及應用技術(shù)
- 石墨烯改性塑料
- Python硬件編程實戰(zhàn)
- Get Your Hands Dirty on Clean Architecture