Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix UI freezing by eliminating EDT-blocking patterns#3102

Open
zenisjan wants to merge 1 commit intogephi:masterfrom
zenisjan:fix/ui-thread-blocking-improvements
Open

Fix UI freezing by eliminating EDT-blocking patterns#3102
zenisjan wants to merge 1 commit intogephi:masterfrom
zenisjan:fix/ui-thread-blocking-improvements

Conversation

@zenisjan
Copy link

This commit addresses critical UI responsiveness issues caused by blocking the Event Dispatch Thread (EDT) during long-running operations.

Critical Issue 1: ProjectControllerImpl Synchronous Execution

Problem

  • LongTaskExecutor was configured for synchronous execution (doInBackground=false)
  • Project operations (open, save, duplicate) blocked the calling thread
  • Broad synchronized blocks caused unnecessary lock contention

Solution

  • Changed LongTaskExecutor to async mode: new LongTaskExecutor(true, "ProjectController", 10)
  • Refactored openProject() to be non-blocking, returning null immediately
  • Refactored duplicateWorkspace() to be non-blocking
  • Refactored saveProject() with proper async pattern
  • Moved synchronized blocks inside lambdas to only lock during state updates
  • Callers should use ProjectListener callbacks for completion notification

Critical Issue 2: Excessive SwingUtilities.invokeAndWait() Usage

Problem

invokeAndWait() blocks the calling thread until EDT completes the runnable, causing UI freezes when called from background threads or during initialization.

Files Fixed

  1. ReportPanel.java & ProcessorIssuesReportPanel.java

    • Changed: Use invokeLater() for deferred UI initialization when not on EDT
  2. EditWindowControllerImpl.java

    • Changed: Added AtomicBoolean cache for isOpen() state
    • Changed: Use invokeLater() instead of invokeAndWait() for state queries
  3. DefaultDataTablesEventListenerBuilder.java

    • Changed: Added AtomicReference cache for DataTablesEventListener
    • Changed: Cache the component reference after first lookup
  4. DesktopImportControllerUI.java

    • Changed: Added explicit EDT checks before invokeAndWait calls
  5. ScreenshotTask.java

    • Changed: Use CompletableFuture with invokeLater() for file chooser dialog
  6. UIUtils.java

    • Changed: Added EDT checks to avoid unnecessary invokeAndWait calls
    • Changed: Added proper Thread.interrupt() handling

Test Updates

  • Updated ProjectControllerImplTest to use CountDownLatch for async operations
  • Tests now properly wait for ProjectListener callbacks before assertions

Breaking Changes

  • openProject(File) now returns null (async) - use ProjectListener.opened()
  • duplicateWorkspace(Workspace) now returns null (async) - workspace auto-selected

This commit addresses critical UI responsiveness issues caused by blocking
the Event Dispatch Thread (EDT) during long-running operations.

## Critical Issue 1: ProjectControllerImpl Synchronous Execution

### Problem
- LongTaskExecutor was configured for synchronous execution (doInBackground=false)
- Project operations (open, save, duplicate) blocked the calling thread
- Broad synchronized blocks caused unnecessary lock contention

### Solution
- Changed LongTaskExecutor to async mode: new LongTaskExecutor(true, "ProjectController", 10)
- Refactored openProject() to be non-blocking, returning null immediately
- Refactored duplicateWorkspace() to be non-blocking
- Refactored saveProject() with proper async pattern
- Moved synchronized blocks inside lambdas to only lock during state updates
- Callers should use ProjectListener callbacks for completion notification

## Critical Issue 2: Excessive SwingUtilities.invokeAndWait() Usage

### Problem
invokeAndWait() blocks the calling thread until EDT completes the runnable,
causing UI freezes when called from background threads or during initialization.

### Files Fixed

1. **ReportPanel.java & ProcessorIssuesReportPanel.java**
   - Changed: Use invokeLater() for deferred UI initialization when not on EDT

2. **EditWindowControllerImpl.java**
   - Changed: Added AtomicBoolean cache for isOpen() state
   - Changed: Use invokeLater() instead of invokeAndWait() for state queries

3. **DefaultDataTablesEventListenerBuilder.java**
   - Changed: Added AtomicReference cache for DataTablesEventListener
   - Changed: Cache the component reference after first lookup

4. **DesktopImportControllerUI.java**
   - Changed: Added explicit EDT checks before invokeAndWait calls

5. **ScreenshotTask.java**
   - Changed: Use CompletableFuture with invokeLater() for file chooser dialog

6. **UIUtils.java**
   - Changed: Added EDT checks to avoid unnecessary invokeAndWait calls
   - Changed: Added proper Thread.interrupt() handling

## Test Updates

- Updated ProjectControllerImplTest to use CountDownLatch for async operations
- Tests now properly wait for ProjectListener callbacks before assertions

## Breaking Changes

- openProject(File) now returns null (async) - use ProjectListener.opened()
- duplicateWorkspace(Workspace) now returns null (async) - workspace auto-selected
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant