Java Threading Mechanism (iii) use of synchronized and volatile

Source: Internet
Author: User
Tags continue thread volatile

Now it's time to get into the most important topic of thread programming---data synchronization, which is the core of thread programming, but also difficult, even if we understand the fundamentals of data synchronization, but we can not guarantee that the correct synchronization code, but the basic principle must be mastered.

To understand the fundamentals of data synchronization, you first need to understand why we want data synchronization?

public class Characterdisplaycanvas extends JComponent implements Characterlistener {protected FontMetrics
    Fm
    Protected char[] Tmpchar = new Char[1];
    
    protected int fontheight;
        Public Characterdisplaycanvas () {SetFont (New Font ("monospaced", Font.Bold, 18));
        fm = Toolkit.getdefaulttoolkit (). Getfontmetrics (GetFont ());
    Fontheight = Fm.getheight ();
        Public Characterdisplaycanvas (Charactersource CS) {this ();
    Setcharactersource (CS);
    public void Setcharactersource (Charactersource cs) {Cs.addcharacterlistener (this);
        Public synchronized void Newcharacter (characterevent CE) {tmpchar[0] = (char) ce.character;
    Repaint (); Dimension preferredsize () {return new Dimension (fm.getmaxascent) + 10 fm.getmaxadvance ()
    );
   } protected synchronized void Paintcomponent (Graphics gc) {Dimension d = getsize ();     Gc.clearrect (0, 0, d.width, d.height);
        if (tmpchar[0] = = 0) {return;
        int charwidth = fm.charwidth ((int) tmpchar[0]);
    Gc.drawchars (Tmpchar, 0, 1, (D.width-charwidth)/2, fontheight); }
}

With a closer look at the code above, we will find that there are two methods in front of a new keyword: synchronized. Let's see why these two methods add this keyword.

Newcharacter () is used to display new letters, and paintcomponent () is responsible for adjusting and redraw canvas. These two methods exist race condition, which is competition, because they are accessing the same data, most importantly, they are called by different threads, which leads us to be unable to guarantee that their invocation is carried out in the correct order, possibly in the Newcharacter () Paintcomponent () method has been redrawn canvas before the method was invoked.

Competition, in addition to the two methods to access the same data, and they are not automic related. When we were in junior high, we learned that atoms were once considered to be the smallest unit, not to be divided, even if it has now proved to be incorrect, but the concept of atomic separation is preserved here on the computer. If a program is considered to be automic, it means that it cannot be interrupted and there is no intermediate state. With synchronized, you can guarantee that the method cannot be interrupted, so other threads cannot call it before the method completes.

With the knowledge of object lock, we can briefly explain the principle of synchronized: If a thread wants to invoke the synchronized method of another thread, and the method is being invoked by another thread, then the thread must wait, Wait for another thread to release the lock on the object that the method is in, and then get the lock to execute the method. The lock mechanism ensures that only one thread at a time can call the method, and that only one thread can access the data.

Remember when we used the tag to end the thread, and we decorated it with volatile? If we don't have to volatile, what can we use?

If only the above knowledge, we may think of using synchronized to synchronize Run () and Setdone (), because it is the two methods in the competition to do this data. But there is a big problem: run () will never end before it is set to true, but the done tag waits until the run () method is finished before it can be set by the Setdone () method.

This is a deadlock that can never be unlocked.

There are many reasons for a deadlock, such as the case above is a typical representative, the main reason is the run () method scope (scope) too large. The term "scope" refers to the time when the lock is acquired, and the scope of the run () method is a loop unless the done is set to true. This method of relying on other threads to end the execution of the method, if the entire method is set to sync, there will be a deadlock.

So the best way to do this is to narrow the scope.

Instead of synchronizing the entire method, we are synchronizing the data that needs to be accessed, that is, using volatile for the done.

To understand how volatile works, we have to be aware of the loading mechanism of the variable. The Java memory model allows a thread to hold the value of a variable in a local memory, so this also causes a thread to change the value of the variable, and other threads may not be aware of the variable's change. This situation is only possible, does not mean that it will occur, but as if this is done in a circular way, it increases this possibility.

So the thing we're going to do is simply to have the thread take the variable out of the same place instead of maintaining it on its own. With volatile, each use of the variable is read from the main memory, and each time the variable is changed, it is also stored in the main memory, and both the load and the storage are automic, whether long or double (both types of storage are not automic).

Notably, the Run () method and the Setdone () method are automic in themselves, because the Setdone () method has only one storage operation, and the run () method has only one read operation, and the remainder requires that the value remain unchanged, that is, There is no competition in the two ways.

Of course, if you insist on using synchronized, there is an ugly way to do it: to provide setter and getter for the done, and then synchronized the two methods, Because a synchronized lock means that all values that are temporarily stored in the register are emptied into the main memory, the run () method must wait until the Setdone () method is set up in order to get done.

What an ugly realization Ah!! In order to synchronize a variable, the result we have to two methods to synchronize, add unnecessary thread overhead!! But this is also no way of things, if we do not know there are volatile words, may also be for their own cleverness and happy unceasingly!!

This is the reality of multithreaded programming, and if we don't know there are more elegant implementations, we can always write code like this.

But what is more puzzling is that the existence of volatile itself is now a cause for concern: is it necessary?

Volatile is implemented with moot point (pending points): variables are always read from primary memory, but this is only before JDK 1.2, the current virtual machine implementation makes the memory pattern more complex and optimized, and this trend will only continue. In other words, volatile based on memory patterns may become meaningless because of the continuous optimization of memory patterns.

The use of volatile is limited, it only solves the problem caused by the memory mode, and can only be used in the automic operation of the variable, that is, the method of accessing the variable can only have a single load or storage. But many of the methods are automic, such as incremental or decrement operations, allowing for intermediate states, because they are the simplicity of loading, altering, and storing, the so-called syntactic sugar (grammatical sugars).

We can probably understand the use of volatile: force the virtual machine not to replicate the variables temporarily, even if we don't use them in many cases.

Can volatile be used on an array so that all elements in the entire array are synchronized? Anyone who uses Java will scoff at this illusion, because the reality is that only the reference to the array will be synchronized, the elements in the array will not be volatile, the virtual machine can still store individual elements in the local register, no There is any way to specify that elements of an array should be handled in a volatile manner.

The problem with our sync above is the display component that shows random numbers and letters, and now we continue to improve the functionality: Players can enter the letters that are displayed and score correctly.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.