JDK-8149007 : Busy loop in other thread delays EDT processing; possible livelock
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: x86_64
  • Submitted: 2016-02-03
  • Updated: 2023-07-21
  • Resolved: 2023-07-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Resolved
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) Server VM (build 25.72-b15, mixed mode)


FULL OS VERSION :
Linux dragon 4.1.12 #5 SMP PREEMPT Tue Dec 29 18:45:31 GMT 2015 x86_64 GNU/Linux
Also seen on Windows, Mac OS X, and Raspberry Pi

A DESCRIPTION OF THE PROBLEM :
A thread executing a busy loop seems to delay execution of the AWT Event Dispatch Thread, despite that there should be no contention between the two threads and the system has unloaded processor cores available. Further, the test case I have provided exhibits 200% processor usage, suggesting that the EDT is in some kind of livelock. Attempts to debug the issue have been futile as JDWP-based debuggers fail to halt the busy thread (tried in Eclipse and Netbeans).

See discussion on Stackoverflow:
http://stackoverflow.com/questions/35154352/busy-loop-in-other-thread-delays-edt-processing/35157351

Test program provided creates a busy loop (which runs for several seconds) when a Swing button is pressed, then displays a JOptionPane dialog after what should be a short delay (500ms sleep). In practice it is seen that either the dialog does not appear (or appears but contents do not render) until after the busy loop has finished (i.e. when it outputs a value to the terminal), or that the dialog does appear but does not respond to input until after the busy loop has finished. Thus it appears that the EDT processing is suspended by execution of the second thread, despite their being no contention between them and despite spare processing cores being available for execution. During this time, the 'top' program on linux shows 200% processor utilisation, which to me suggests livelock (or at least unexpected starvation) in the EDT.

Problem is suppressed by using -Xint. On some but not all systems problem can be suppressed using -client.


THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Execute sample program provided with this report
2. Click "Try me" button
3. Click any button (yes/no/cancel) to close the resulting dialog


EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected:
Between steps 2 and 3, there should be an approx 500ms delay before a dialog is displayed.
After step 3, the dialog should close immediately.

Actual:
Between steps 2 and 3, there may be a long delay before the dialog appears visible, or it may appear on time but not rendered until some time later.
After step 3, the dialog may not close until after a long delay.

REPRODUCIBILITY :
This bug can be reproduced often.

---------- BEGIN SOURCE ----------
import java.awt.EventQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MFrame extends JFrame
{
    public static void main(String[] args)
    {
        EventQueue.invokeLater(() -> {
            new MFrame();
        });
    }

    public MFrame()
    {
        JButton tryme = new JButton("Try me!");

        tryme.addActionListener((e) -> {
            Thread t = new Thread(() -> {
                int a = 4;
                for (int i = 0; i < 100000; i++) {
                    for (int j = 0; j < 100000; j++) {
                        a *= (i + j);
                        a += 7;
                    }
                }
                System.out.println("a = " + a);
            });

            t.start();

            // Sleep to give the other thread a chance to get going.
            // (Included because it provokes the problem more reliably,
            // but not necessary; issue still occurs without sleep call).
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException ie) {
                ie.printStackTrace();
            }

            // Now display a dialog
            JOptionPane.showConfirmDialog(null, "You should see this immediately");
        });

        getContentPane().add(tryme);

        pack();
        setVisible(true);
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Using Thread.yield() within the busy loop will suppress the problem.


Comments
Yes, it is a long standing known problem with long running counted loops (JDK-5014723). There's a workaround: recently added -XX:+UseCountedLoopSafepoints keeps safepoints in counted loops (it has negative performance impact though).
29-02-2016

Theory seems to be confirmed: /scratch/dh198349/tests > java -XX:+SafepointTimeout MFrame # SafepointSynchronize::begin: Timeout detected: # SafepointSynchronize::begin: Timed out while spinning to reach a safepoint. # SafepointSynchronize::begin: Threads which did not reach the safepoint: # "Thread-0" #24 prio=6 os_prio=0 tid=0x9f2f4000 nid=0x5781 runnable [0x00000000] java.lang.Thread.State: RUNNABLE # SafepointSynchronize::begin: (End of list) a = 1838603747 > java -version java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) Server VM (build 25.0-b70, mixed mode) Same with latest JDK 9: java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+103-2016-01-27-180503.javare.4341) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+103-2016-01-27-180503.javare.4341, mixed mode) # SafepointSynchronize::begin: Timeout detected: # SafepointSynchronize::begin: Timed out while spinning to reach a safepoint. # SafepointSynchronize::begin: Threads which did not reach the safepoint: # "Thread-0" #26 prio=6 os_prio=0 tid=0x00007fcd68553800 nid=0x6831 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE # SafepointSynchronize::begin: (End of list) a = 1838603747 Seems fine with -Xint and -client. Reproduces with -server and -server with Xcomp. Moving to compiler team, but I suspect this is a known issue.
04-02-2016

Theory: the busy loop is being compiled into a form that is missing safepoint checks. If that happens the other busy thread will be the VMThread. The EDT will be blocked until the safepoint is over. To test that theory increase the workload in the busy loop and see if it triggers the VMThread to hit guarantee (PageArmed == 0, "invariant") ; You could also try setting -XX:+SafepointTimeout and playing with -XX:SafepointTimeoutDelay to see if you trigger a safepoint timeout. -Xlog:trace=safepoint in latest JDK 9 may also be informative.
04-02-2016

This is an issue, Below are the observation Event Dispatcher Thread delays the processing, Should have responded immediately Step 1. Execute sample program Step 2. Click "Try me" button Step 3. Click any button (yes/no/cancel) to close the resulting dialog On Windows == Long delay observe between Step 2 and Step 3 Step 3 -> Closes the dialog immediatly On Linux == Step 2 to Step 3 No delay Step 3 -> Long delay to close the dialog Test executed on Below builds. 8 - Fail 8u72 - Fail 8u66 - Fail 9 ea b-103 - Fail
04-02-2016