Duplicate :
|
Name: jl125535 Date: 11/11/2002 FULL PRODUCT VERSION : java version "1.4.1" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21) Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode) FULL OPERATING SYSTEM VERSION : Microsoft Windows XP [Version 5.1.2600] ADDITIONAL OPERATING SYSTEMS : Windows 2000 sp2 A DESCRIPTION OF THE PROBLEM : Under certain conditions, the setText(String) method of JTextComponent/JFormattedTextField does not appear to be thread safe in spite of JDK documentation indicating that it is. Deadlock can occur at seemingly random times. Because this is a multithreaded, timing dependent, issue different hardware platforms may experience different results. STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : 1. Compile and run the demo application. 2. Click the test button. The application may lock immediately or it may lock on a subsequent click. 3. If it does not lock, you can also try changing the timing of the Thread.sleep() methods and/or clicking multiple times in succession. EXPECTED VERSUS ACTUAL BEHAVIOR : The application should not lock up. ERROR MESSAGES/STACK TRACES THAT OCCUR : There are no error messages. REPRODUCIBILITY : This bug can be reproduced often. ---------- BEGIN SOURCE ---------- /* This class demonstrates that a JFormattedTextField's inherited setText method is not thread-safe. It is also conceivable that JTextComponent's setText method will not be thread-safe even when it is not being used as the super class of a JFormattedTextField. This class demonstrates thread deadlock occuring when a background thread is attempting to update the JFormattedTextField while the dispatch thread is painting. The deadlock evidently arises because the painting thread has acquired the AWTTreeLock before entering AbstractDocument.readLock(). The painting thread waits forever in readLock so that the background thread can finish editing. However, the background thread may call TextComponent.fireCaretUpdate which causes it to hang in subsequent method Component.AccessibleAWTComponent.getLocationOnScreen() because the latter needs to synchronize on the AWTTreeLock. */ import javax.swing.*; import javax.swing.text.*; import javax.accessibility.AccessibleContext; import java.awt.event.*; import java.awt.*; public class FormattedTextTest extends JFrame { private AccessibleContext ac; private JFormattedTextField fld; private JPanel basePanel; private String[] values = new String[]{ "one, one", "two, two", "three, three", "four, four"}; public static final void main (String[] args){ FormattedTextTest t = new FormattedTextTest(); t.show(); } /* Construct a simple dialog to use for a test platform. */ public FormattedTextTest(){ super(); setDefaultCloseOperation(DISPOSE_ON_CLOSE); JButton testButton = new JButton("Test"); testButton.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ test(); } }); fld = new JFormattedTextField(); fld.setPreferredSize(new Dimension(40, 20)); /* Similar code is called from BasicComboBoxUI in the original application code. It causes CaretListeners to be registered. */ ac = fld.getAccessibleContext(); /* Installing our own formatter seems to be important in this scenario. JFormattedTextField may take a different path through the code when a formatter has been installed. */ DefaultFormatter formatter = new DefaultFormatter(); DefaultFormatterFactory dff = new DefaultFormatterFactory(formatter); fld.setFormatterFactory(dff); basePanel = new JPanel(); basePanel.add(testButton); basePanel.add(fld); getContentPane().add(basePanel); pack(); } /* Launch a background thread to repeatedly modify the field. Then use the current (dispatch) thread to repeatedly paint the field. */ private void test(){ Thread thread = new Thread(new ValueSetter()); thread.start(); /* Deadlock occurs when the edit thread and the paint thread are in just the right phase of execution. A varying timing loop on both threads helps to increase the chances of this occurring. If it doesn't occur on your machine, try adding more loops here and/or clicking the button multiple times so that multiple background threads will be updating the field simultaneously. */ // Invoking revalidate() and paintImmediately() from the event // dispatching thread should be safe. for (int n = 0; n < 40; n ++){ basePanel.revalidate(); basePanel.paintImmediately(basePanel.getBounds()); try{ Thread.sleep(n); } catch (InterruptedException e){} } } private class ValueSetter implements Runnable{ public void run(){ for (int i = 0; i < 10; i++){ for (int j = 0; j < values.length; j++){ //this causes deadlock fld.setText(values[j]); //this alternative appears to be safe //fld.setValue(values[j]); try{ Thread.sleep(i + j); } catch (InterruptedException e){} } } } } } ---------- END SOURCE ---------- CUSTOMER WORKAROUND : These *appear* to work but haven't been thoroughly tested. 1. Don't install Formatter and FormatterFactory. 2. Use the setValue method instead of the setText method. (Review ID: 166755) ======================================================================