Chapter 3 data synchronization Reading Notes

Source: Internet
Author: User


Data sharing among multiple threads
1. The word atomic of Synchronized has nothing to do with "atom". It was once considered to be the smallest unit of matter and cannot be split into smaller parts. When a method is declared as synchronized, the thread that executes this method must first obtain a token, which is called a lock. Once this method gets (or gets) the lock, it will run this method and then release (or return) the lock. No matter how the method returns (including through exceptions), the lock will be released.
2. Volatile keywords if a variable is labeled as volatile, it must be read from the main register every time it is used. Similarly, each time you write this variable, the value must be stored in the main register. Furthermore, Java specifies that the loading and storage of volatile variables are atomic, whether long or double. Variables declared by volatile ++ and -- operations cannot guarantee atomicity. The array declared by volatile changes the array reference to the element in the volatile array instead of volatile.
Iii. More discussion on competitive conditions

public class ScoreLabel extends JLabel implements CharacterListener {        private volatile int score = 0;    private int char2type = -1;    private CharacterSource generator = null, typist = null;    public ScoreLabel (CharacterSource generator, CharacterSource typist) {        this.generator = generator;        this.typist = typist;        if (generator != null)            generator.addCharacterListener(this);        if (typist != null)             typist.addCharacterListener(this);           }    public ScoreLabel () {        this(null, null);    }    public synchronized void resetGenerator(CharacterSource newGenerator) {        if (generator != null)            generator.removeCharacterListener(this);        generator = newGenerator;        if (generator != null)            generator.addCharacterListener(this);            }    public synchronized void resetTypist(CharacterSource newTypist) {        if (typist != null)            typist.removeCharacterListener(this);        typist = newTypist;        if (typist != null)            typist.addCharacterListener(this);    }    public synchronized void resetScore() {        score = 0;        char2type = -1;        setScore();    }    private void setScore() {        // This method will be explained later in chapter 7        SwingUtilities.invokeLater(new Runnable() {            public void run() {                setText(Integer.toString(score));            }        });    }    public synchronized void newCharacter(CharacterEvent ce) {        // Previous character not typed correctly - 1 point penalty        if (ce.source == generator) {            if (char2type != -1) {                score--;                setScore();            }            char2type = ce.character;        }        // If character is extraneous - 1 point penalty        // If character does not match - 1 point penalty        else {            if (char2type != ce.character) {                score--;           } else {               score++;               char2type = -1;           }           setScore();       }    } }


Such shared data is composed of the actual scores, the letters to be entered, and a few held letter sources as registration variables. Resolving the race condition means synchronizing the data in the correct scope. If the newCharacter method cannot be synchronized, the modification of the variables char2type and score contained in the newCharacter method cannot be ensured that the correct last modified value can be obtained in real time in all threads, this leads to problems based on the char2type judgment, and also causes problems in scores. The solution is to use the current class as the synchronization lock for all variables involved in this class (that is, a synchronized keyword is added for each method ), the purpose is to call these methods in all threads if they are mutex operations. It is impossible for multiple threads to call the methods that operate these two variables at the same time to ensure correctness.

Iv. Display lock
public class ScoreLabel extends JLabel implements CharacterListener {        private volatile int score = 0;    private int char2type = -1;    private CharacterSource generator = null, typist = null;    private Lock scoreLock = new ReentrantLock();    public ScoreLabel (CharacterSource generator, CharacterSource typist) {        this.generator = generator;        this.typist = typist;        if (generator != null)            generator.addCharacterListener(this);        if (typist != null)             typist.addCharacterListener(this);           }    public ScoreLabel () {        this(null, null);    }    public void resetGenerator(CharacterSource newGenerator) {        try {            scoreLock.lock();            if (generator != null)                generator.removeCharacterListener(this);            generator = newGenerator;            if (generator != null)                generator.addCharacterListener(this);        } finally {            scoreLock.unlock();        }    }    public void resetTypist(CharacterSource newTypist) {        try {            scoreLock.lock();            if (typist != null)                typist.removeCharacterListener(this);            typist = newTypist;            if (typist != null)                typist.addCharacterListener(this);        } finally {            scoreLock.unlock();        }    }    public void resetScore() {        try {            scoreLock.lock();            score = 0;            char2type = -1;            setScore();        } finally {            scoreLock.unlock();        }    }    private void setScore() {        // This method will be explained later in chapter 7        SwingUtilities.invokeLater(new Runnable() {            public void run() {                setText(Integer.toString(score));            }        });    }    public void newCharacter(CharacterEvent ce) {        try {            scoreLock.lock();            // Previous character not typed correctly - 1 point penalty            if (ce.source == generator) {                if (char2type != -1) {                    score--;                    setScore();                }                char2type = ce.character;            }            // If character is extraneous - 1 point penalty            // If character does not match - 1 point penalty            else {                if (char2type != ce.character) {                    score--;                } else {                    score++;                    char2type = -1;                }                setScore();            }        } finally {            scoreLock.unlock();        }    } }


The same principle as in the previous example, the locks are applied to both char2type and score variable modification methods, the current example only uses the Lock and unLock provided by another syntax to Lock and unLock the operation. In this example, the two methods are equivalent. The differences between synchronized and Lock will be discussed later.
5. Lock Scope
public class ScoreLabel extends JLabel implements CharacterListener {        private volatile int score = 0;    private int char2type = -1;    private CharacterSource generator = null, typist = null;    private Lock scoreLock = new ReentrantLock();    public ScoreLabel (CharacterSource generator, CharacterSource typist) {        this.generator = generator;        this.typist = typist;        if (generator != null)            generator.addCharacterListener(this);        if (typist != null)             typist.addCharacterListener(this);           }    public ScoreLabel () {        this(null, null);    }    public void resetGenerator(CharacterSource newGenerator) {        try {            scoreLock.lock();            if (generator != null)                generator.removeCharacterListener(this);            generator = newGenerator;            if (generator != null)                generator.addCharacterListener(this);        } finally {            scoreLock.unlock();        }    }    public void resetTypist(CharacterSource newTypist) {        try {            scoreLock.lock();            if (typist != null)                typist.removeCharacterListener(this);            typist = newTypist;            if (typist != null)                typist.addCharacterListener(this);        } finally {            scoreLock.unlock();        }    }    public void resetScore() {        try {            scoreLock.lock();            score = 0;            char2type = -1;            setScore();        } finally {            scoreLock.unlock();        }    }    private void setScore() {        // This method will be explained later in chapter 7        SwingUtilities.invokeLater(new Runnable() {            public void run() {                setText(Integer.toString(score));            }        });    }    public void newCharacter(CharacterEvent ce) {        if (ce.source == generator) {            try {                scoreLock.lock();                // Previous character not typed correctly - 1 point penalty                if (char2type != -1) {                    score--;                    setScore();                }                char2type = ce.character;            } finally {                scoreLock.unlock();            }        }        // If character is extraneous - 1 point penalty        // If character does not match - 1 point penalty        else {            try {                scoreLock.lock();                if (char2type != ce.character) {                    score--;                } else {                    score++;                    char2type = -1;                }                setScore();            } finally {                scoreLock.unlock();            }        }    } }



Lock and unLock can be placed anywhere you need.
6. Synchronized Block
public class ScoreLabel extends JLabel implements CharacterListener {        private volatile int score = 0;    private int char2type = -1;    private CharacterSource generator = null, typist = null;    public ScoreLabel (CharacterSource generator, CharacterSource typist) {        this.generator = generator;        this.typist = typist;        if (generator != null)            generator.addCharacterListener(this);        if (typist != null)             typist.addCharacterListener(this);           }    public ScoreLabel () {        this(null, null);    }    public synchronized void resetGenerator(CharacterSource newGenerator) {        if (generator != null)            generator.removeCharacterListener(this);        generator = newGenerator;        if (generator != null)            generator.addCharacterListener(this);            }    public synchronized void resetTypist(CharacterSource newTypist) {        if (typist != null)            typist.removeCharacterListener(this);        typist = newTypist;        if (typist != null)            typist.addCharacterListener(this);    }    public synchronized void resetScore() {        score = 0;        char2type = -1;        setScore();    }    private void setScore() {        // This method will be explained later in chapter 7        SwingUtilities.invokeLater(new Runnable() {            public void run() {                setText(Integer.toString(score));            }        });    }    public void newCharacter(CharacterEvent ce) {        // Previous character not typed correctly - 1 point penalty        if (ce.source == generator) {            synchronized(this) {                if (char2type != -1) {                    score--;                    setScore();                }                char2type = ce.character;            }        }        // If character is extraneous - 1 point penalty        // If character does not match - 1 point penalty        else {            synchronized(this) {                if (char2type != ce.character) {                    score--;               } else {                   score++;                   char2type = -1;               }               setScore();            }        }    } }



In this example, the locked object and the synchronized object used in the method are the same: this object.
7. Selecting the Locking mechanism synchronized differs from Lock in the static method, because synchronized is used in the method to Lock the current object, while the static method is global, using this method will increase the difficulty of ensuring correctness. Instead, you can use Lock because it has nothing to do with the current object. You only need to set lock and unlock In the method, so it is easier to ensure the correctness of multi-thread synchronization.
8. Lock Interface
Boolean tryLock ()
The lock is obtained only when the lock is idle.
If the lock is available, the lock is obtained and the return value is true immediately. If the lock is unavailable, this method immediately returns false.

The typical statements used in this method are as follows:

Lock lock = ...;
If (lock. tryLock ()){
Try {
// Manipulate protected state
} Finally {
Lock. unlock ();
}
} Else {
// Perform alternative actions
}
This usage ensures that the lock is released if it is obtained. If it is not obtained, it will not try to release it.

Return Value:
If the lock is obtained, true is returned; otherwise, false is returned.


9. Nested Lock
public class ScoreLabel extends JLabel implements CharacterListener {        private volatile int score = 0;    private int char2type = -1;    private CharacterSource generator = null, typist = null;    public ScoreLabel (CharacterSource generator, CharacterSource typist) {        this.generator = generator;        this.typist = typist;        if (generator != null)            generator.addCharacterListener(this);        if (typist != null)             typist.addCharacterListener(this);           }    public ScoreLabel () {        this(null, null);    }    public synchronized void resetGenerator(CharacterSource newGenerator) {        if (generator != null)            generator.removeCharacterListener(this);        generator = newGenerator;        if (generator != null)            generator.addCharacterListener(this);            }    public synchronized void resetTypist(CharacterSource newTypist) {        if (typist != null)            typist.removeCharacterListener(this);        typist = newTypist;        if (typist != null)            typist.addCharacterListener(this);    }    public synchronized void resetScore() {        score = 0;        char2type = -1;        setScore();    }    private void setScore() {        // This method will be explained later in chapter 7        SwingUtilities.invokeLater(new Runnable() {            public void run() {                setText(Integer.toString(score));            }        });    }    private synchronized void newGeneratorCharacter(int c) {        if (char2type != -1) {            score--;            setScore();        }        char2type = c;    }    private synchronized void newTypistCharacter(int c) {        if (char2type != c) {            score--;        } else {            score++;            char2type = -1;        }        setScore();    }    public synchronized void newCharacter(CharacterEvent ce) {        // Previous character not typed correctly - 1 point penalty        if (ce.source == generator) {    newGeneratorCharacter(ce.character);        }        // If character is extraneous - 1 point penalty        // If character does not match - 1 point penalty        else {    newTypistCharacter(ce.character);        }    } }



Synchronized Locking is reentrant, that is, when other synchronized methods of this class are called in the current declared synchronized method, they can be directly accessed without the need to obtain the lock again.
Public int getHoldCount () queries the number of times the current thread keeps the lock.
For each lock operation that does not match the unlock operation, the thread will keep a lock.

The keep count information is usually only used for testing and debugging. For example, if you should not use a locked lock to enter a part of the code, you can declare it as follows:

class X {   ReentrantLock lock = new ReentrantLock();   // ...        public void m() {      assert lock.getHoldCount() == 0;     lock.lock();     try {       // ... method body     } finally {       lock.unlock();     }   }}

Return Value:
The number of times the current thread keeps the lock. If the lock has not been retained by the current thread, 0 is returned.
10. A deadlock occurs when two or more threads are waiting for two or more locks to be released, and the program environment keeps the lock from being released.
11. How should the Lock be granted when the lock is used with a clear lock? 1. Let the lock be granted with the principle of first-come-first-served. 2. authorize it in the order that it can serve the most requests. 3. The lock should be granted to the system in the most favorable form, no matter what it is used. (Synchronized is close to this)




Related Article

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.