Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could someone please explain "Note: This method should be called under AWT tree lock."?

Tags:

java

swing

awt

I am trying to make my program read the answers entered into a questionnaire-like form. For this purpose I plan to use getComponents() to get the answer fields I require (e.g. text fields, radio buttons, etc.), and then use methods like getText() to read the answers.

I have never used getComponents() and am just learning Java/Swing/AWT. The above warning in the documentation for getComponents() intimidates me, because I have no idea what a "tree lock" is, or where to find out what it is. Google has yielded nothing.

Even if getComponents() turns out to be an inappropriate solution to my problem, for the sake of learning I would still like my question answered.

Thanks! :)

like image 461
Fungixl Avatar asked Nov 25 '15 22:11

Fungixl


People also ask

Which method puts components into the container in AWT?

add. Adds the specified component to this container at the given position. This is a convenience method for addImpl(java. awt.

What is the return type of getAlignmentX () method?

The getAlignmentX() method returns the alignment of the component along the x axis. The alignment could be used by a layout manager to position this component relative to others. The return value is between 0.0 and 1.0.

Which of the following methods can be used to remove Java AWT component object from display?

The hide feature is used to remove java AWT a component object from the display.


1 Answers

I was also curious about the inner workings of the AWT tree lock (AWTTreeLock/TreeLock) so I did some research which I will try to summarize here.

First of all bear in mind, that in Swing one should only access Components on the AWT Event Dispatch Thread (EDT) (see Swing's Threading Policy). Therefore it is generally recommended to always prefere SwingUtilities#invokeLater() instead of Component#getTreeLock() for GUI synchronization tasks. If one can guarantee, that all access to the GUI components is done on the EDT, there should usually be no need to explicitly synchonize on Component#getTreeLock().

According to David Holmes AWT was on the other hand originally intended to be accessible by multiple threads, which might also explain why the Javadoc of strict AWT classes (e.g. Component and Container) do not inclcude the thread-safety warning usually found in the Javadoc of Swing classes ("Swing is not thread safe..."). In this regard Component#getTreeLock() returns the static final lock Object shared by all AWT components. AWT classes synchronize on this object when modifying/accessing the component tree (e.g. during Container#addImpl()) and it is the client's responsibility to synchronize on this lock when multiple threads access the component tree. From this point of view Component#getTreeLock() seems to be a relict from this original AWT design and today mainly exists for backward compatibility and arguably for some border case uses like e.g. accessing components from multiple threads before the AWT event dispatch thread has started. On the other hand additional synchronization on the tree lock doesn't hurt either in some cases (I guess the small performance penalty can easily be neglected) - e.g. I'd still recommend tree lock synchronization during calls to Container#getComponents(), Container#getComponentCount() and Container#getComponent(int) (as documented in the Javadoc of these methods) and possibly also during layout operations in Java LayoutManagers (as suggested in the Javadoc of Component#getTreeLock() - actually these two rules are more or less the same, since most of the time LayoutManagers make use of exactly these three methods).

Available documentation and information about the AWT tree lock

It's a shame that a public Java API method intended for GUI thread synchronization is so poorly documented. Actually it seems the only "documentation" is provided by the Javadoc of Component#getTreeLock() itself, which might very well be listed as a good example for bad practice getter documentation:

/**
 * Gets this component's locking object (the object that owns the thread
 * synchronization monitor) for AWT component-tree and layout
 * operations.
 * @return this component's locking object
 */

Other than that there are some hints about the intended usage of the tree lock in the documentation of Container#getComponents(), Container#getComponentCount() and Container#getComponent(int).

Note: This method should be called under AWT tree lock.

and in the source code comments of some Java classes referencing Component#getTreeLock() like e.g. java.swing.GroupLayout:

public void invalidateLayout(Container parent) {
    checkParent(parent);
    // invalidateLayout is called from Container.invalidate, which
    // does NOT grab the treelock.  All other methods do.  To make sure
    // there aren't any possible threading problems we grab the tree lock
    // here.
    synchronized(parent.getTreeLock()) {
    [...]

One interesting detail here is, that Java LayoutManagers do most of the time synchronize on the tree lock when doing layout operations - e.g. in the methods layoutContainer(), minimumLayoutSize() and preferredLayoutSize() of FlowLayout, BorderLayout and GridLayout. But strangely enough this pattern is not consistently applied to all Java LayoutManagers - e.g. GridBagLayout does synchronize on the tree lock in the method getLayoutInfo() but does not do so in the method arrangeGrid(), although both methods access the component tree. BoxLayout on the other hand does not synchronize on the tree lock at all (see also this thread). FWIW the Java tutorial for Creating a Custom Layout Manager does not mention tree locks at all and the given example does not do any synchronization. Still, a lot of third party LayoutManagers also adhere to this synchronization pattern like e.g. JGoodies FormLayout and the Custom Layouts Blog says that

Synchronizing on the object returned by the container's getTreeLock method ensures thread safety while performing the layout

In my opinion this inconsistency and the lack of proper documentation is very confusing. E.g. I still have no idea under which circumstances it would absolutely be necessary for LayoutManagers to synchronize on the tree lock. I'd guess that normally (i.e. if component access stays on the EDT) synchronization should not be necessary. On the other hand this extra bit of synchronization certainly doesn't hurt either...

Also Java bug JDK-6784816 provides some information on the subject. It states that

AWT tree lock is a public lock that should be used for any hiearchy or layout operations by developers, not by AWT.

and that

applications that call them [the methods Container#getComponents(), Container#getComponentCount() and Container#getComponent(int)] without AWT tree lock must realize that they do this on their own risk. For example, due to some timings changes, the methods may return incorrect values without proper synchronization under AWT tree lock.

I would still strongly advice against solely relying on tree lock synchronization instead of synchronization on the EDT, considering the inconsistent synchronization on the tree lock that can be found in the Java API alone (not to mention possible third party API's). I'll conclude with Thomas Hawtins words on this subject:

Swing is single threaded, AWT is not. However, AWT has thousands (literally) of threading bugs, which are unlikely to be fixed. It is unreasonable to expect multithreaded AWT application code not to be completely broken.


Further references and links

  • validateTree in Java 7.x doesnt work (in Java 6.x was fine)
  • System.exit is not thread-safe on Linux?
  • getTreeLock() thread on coderanch
  • GetTreelock thread on codeguru
like image 174
Balder Avatar answered Sep 18 '22 13:09

Balder