Java线程睡眠表现不符预期,求代码问题排查
Hey there! Let's break down why your loop isn't updating the textArea every second like you expected, and how to fix this issue.
The Root Cause
Swing follows a single-threaded model—all UI updates and user event handling run on the Event Dispatch Thread (EDT). When you call Thread.sleep(1000) directly inside your loop, you're blocking the EDT completely.
Here's what's really happening:
- Every time you call
textArea.setText(...), Swing queues a UI update request, but the EDT is stuck sleeping and can't process it. - After 10 full iterations (10 seconds of sleep total), the loop finishes, and the EDT finally frees up to handle all those queued update requests at once. That's why you see all the updates happen suddenly, like the
sleepnever ran at all.
Fix 1: Use Swing Timer (Best for Simple Timed UI Updates)
Swing's Timer is built exactly for this scenario—it triggers events on the EDT at regular intervals without blocking it. Here's how to rewrite your code:
import javax.swing.Timer; // Initialize iteration counter and timer int iterationCount = 0; Timer updateTimer = new Timer(1000, event -> { if (iterationCount < 10) { // Use append() instead of setText() if you want to keep all iterations visible textArea.setText("\n***Iterate***\n"); // textArea.append("\n***Iterate***\n"); iterationCount++; } else { // Stop the timer once we've completed 10 iterations ((Timer) event.getSource()).stop(); } }); // Start the timer to begin updates updateTimer.start();
Fix 2: Use SwingWorker (For Background Work + UI Updates)
If you ever need to run longer background tasks (not just sleep) alongside UI updates, use SwingWorker. It safely separates background work from UI updates:
import javax.swing.SwingWorker; import java.util.List; new SwingWorker<Void, String>() { // Runs in a background thread (not the EDT) to avoid blocking UI @Override protected Void doInBackground() throws InterruptedException { for (int i = 0; i < 10; i++) { // Send text to the UI update method publish("\n***Iterate***\n"); Thread.sleep(1000); } return null; } // Runs on the EDT—safe to update UI components here @Override protected void process(List<String> chunks) { for (String updateText : chunks) { textArea.setText(updateText); // Or use append() to retain all iteration text // textArea.append(updateText); } } }.execute();
Quick Tip: setText() vs append()
Your original code uses setText(), which overwrites the entire content of textArea each time. If you want to see every iteration's text added to the area instead of replaced, swap setText() with append().
内容的提问来源于stack exchange,提问作者user311699

