Changes in Threading Framework in IntelliJ Platform 2025.2

Hello everyone!

We would like to share with you important updates of the threading framework in IntelliJ Platform 2025.2.

The most notable change of this release is that we are starting to execute some write actions on background. This functionality still remains internal, as we need to ensure that the Platform works smoothly with this new setup. For now, only certain write actions on project startup are changed for background execution. Write actions on UI thread will be supported further.
If you feel that it brings any problems, consider setting the system property -Didea.background.write.action.enabled=false for your IDE. Typical example of problems is that some of the listeners for MessageBus topics that were meant to run on EDT may run on background threads. Don’t hesitate to reach out if you have any feedback.

Other changes in the threading framework:

  1. If a thread is blocked on acquisition of the Read/Write lock, then it will react to external cancellation and throw an instance of CancellationException without proceeding further. This is similar to prompt cancellation guarantee from kotlin coroutines library.
    It means that the following code:
coroutineScope {
  launch(Dispatchers.EDT) {
    runWriteAction { 
      // long operation
    }
  }
  val job = launch(Dispatchers.Default) {
    runReadAction {}
  }
  job.cancelAndJoin() // <- this will be promptly completed because lock acquisition in `runReadAction` is now cancellable.
}
  1. suspend fun readAction is no longer rescheduled with invokeLater (IJPL-186444). It may cause increased number of cancellations in your code. Unfortunately there is no easy way to diagnose it, but replacing readAction with runReadAction may help.

  2. Sometimes you may see deadlocks that mention blockingWaitForCompositeFileOpen. Most likely, it means that you are opening a file under write lock (like in com.intellij.openapi.fileEditor.FileNavigator#navigate). In this case, consider making opening of the file asynchronous, i.e., surround your navigation logic with Application.invokeLater.

  3. ApplicationListener.beforeWriteActionStart, ApplicationListener.writeActionStarted, ApplicationListener.writeActionFinished, ApplicationListener.afterWriteActionFinished now may be invoked on a background thread instead of only EDT. Consider removing access to UI from your listeners or delay it with Application.invokeLater.

  4. currentThreadCoroutineScope is now stable and it can be invoked only when there is an outer withCurrentThreadCoroutineScope. It is fine to continue using this function inside AnAction.actionPerformed.

  5. Functions runBlockingCancellable, currentThreadCoroutineScope, and coroutineToIndicator are promoted to stable.

  6. blockingContext is now no-op and deprecated (IJPL-445). Since 2025.2 IntelliJ platform manages thread contexts automatically.

1 Like

Hi, is it already testable with the latest 2025.2 EAP?

Hi Jonathan,
Yes, it is.

1 Like