Java 螺纹第三版 第三章数据同步 读书笔记
多線程間共享數(shù)據(jù)問題
一、Synchronizedkeyword
atomic一詞與“原子”無關(guān),它以前被覺得是物質(zhì)的最小的單元,不能再被拆解成更小的部分。 當一個方法被聲明成synchronized,要執(zhí)行此方法的thread必須先取得一個token,我們將它稱為鎖。一旦該方法取得(或者說是獲得)鎖,它將執(zhí)行此方法然后釋放掉(或者返回)此鎖。無論方法時如何返回的(包含通過異常)該鎖會被釋放。 ? ??
二、Volatilekeyword
假設(shè)變量被標示為volatile。每次使用該變量時都必須從主寄存器中讀出。同樣地。每次要寫入該變量時,值都必須存入主寄存器。更進一步。Java指定對volatile變量的載入與存儲都是atomic的。不管是否是long與double變量。 volatile聲明的變量進行++、--操作不能保證原子性。 volatile聲明的數(shù)組,會讓數(shù)組的引用變成volatile數(shù)組中的元素不是volatile。三、很多其它競態(tài)條件的討論
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 7SwingUtilities.invokeLater(new Runnable() {public void run() {setText(Integer.toString(score));}});}public synchronized void newCharacter(CharacterEvent ce) {// Previous character not typed correctly - 1 point penaltyif (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 penaltyelse {if (char2type != ce.character) {score--;} else {score++;char2type = -1;}setScore();}} }此類共享的數(shù)據(jù)是由實際的得分數(shù)、須要被輸入的字母與少數(shù)持有的字母來源作為登記用的變量等所組成。解決競態(tài)條件問題意味著讓這些數(shù)據(jù)在正確的scope中被同步化。 假設(shè)newCharacter方法不能確保同步。當中包括的變量char2type、score變量的改動并不能保證在全部的線程中都能實時的獲取到正確的最后一次改動的值,導(dǎo)致基于char2type的推斷出現(xiàn)故障,接連導(dǎo)致score也出現(xiàn)故障。 解決的方法是在此類中全部涉及到這兩個變量的都把當前類作為同步鎖(即每一個方法都加入一個synchronizedkeyword)。目的是在全部線程中調(diào)用這些方法都必需要是相互排斥操作,不可能同一時候多個線程調(diào)用操作這兩個變量的方法,從而保證正確性。
四、顯示鎖
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 7SwingUtilities.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 penaltyif (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 penaltyelse {if (char2type != ce.character) {score--;} else {score++;char2type = -1;}setScore();}} finally {scoreLock.unlock();}} }與上一個樣例原理同樣,都是涉及char2type、score兩個變量改動的方法上都加入鎖,當前樣例僅是使用第二種語法使用提供的Lock與unLock來加鎖解鎖操作,在此樣例上這兩種做法是等價的。之后會討論synchronized與Lock的不同之處。
五、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 7SwingUtilities.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 penaltyif (char2type != -1) {score--;setScore();}char2type = ce.character;} finally {scoreLock.unlock();}}// If character is extraneous - 1 point penalty// If character does not match - 1 point penaltyelse {try {scoreLock.lock();if (char2type != ce.character) {score--;} else {score++;char2type = -1;}setScore();} finally {scoreLock.unlock();}}} }Lock與unLock能夠放到自己須要的不論什么地方。
六、Synchronized塊
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 7SwingUtilities.invokeLater(new Runnable() {public void run() {setText(Integer.toString(score));}});}public void newCharacter(CharacterEvent ce) {// Previous character not typed correctly - 1 point penaltyif (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 penaltyelse {synchronized(this) {if (char2type != ce.character) {score--;} else {score++;char2type = -1;}setScore();}}} }在此樣例中,被鎖住的對象與用在方法的同步化上的是同一個對象:this對象。 ? ??
七、選擇Locking機制
synchronized與Lock在靜態(tài)方法(static method)上有所差別,由于在方法上使用synchronized是針對當前對象鎖定。而靜態(tài)方法是全局的,使用這樣的辦法會使確保正確性添加難度,相反使用Lock由于它與當前對象無關(guān)。僅僅須要在方法內(nèi)設(shè)置lock與unlock所以更easy確保多線程同步的正確性。八、Lock Interface
boolean tryLock()
???? 僅在調(diào)用時鎖為空暇狀態(tài)才獲取該鎖。?
???? 假設(shè)鎖可用,則獲取鎖,并馬上返回值 true。
假設(shè)鎖不可用。則此方法將馬上返回值 false。?
???? 此方法的典型使用語句例如以下:?
????? Lock lock = ...;
????? if (lock.tryLock()) {
????????? try {
????????????? // manipulate protected state
????????? } finally {
????????????? lock.unlock();
????????? }
????? } else {
????????? // perform alternative actions
????? }
???? 此使用方法可確保假設(shè)獲取了鎖。則會釋放鎖,假設(shè)未獲取鎖,則不會試圖將其釋放。
?
???? 返回:
???? 假設(shè)獲取了鎖,則返回 true;否則返回 false。
九、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 7SwingUtilities.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 penaltyif (ce.source == generator) {newGeneratorCharacter(ce.character);}// If character is extraneous - 1 point penalty// If character does not match - 1 point penaltyelse {newTypistCharacter(ce.character);}} }synchronized鎖定是可重入的。即當前聲明?synchronized的方法中調(diào)用此類的其它?synchronized方法時能夠直接進入,無需再次獲取鎖操作。
public int getHoldCount() ???? 查詢當前線程保持此鎖的次數(shù)。?
???? 對于與解除鎖操作不匹配的每一個鎖操作。線程都會保持一個鎖。?
???? 保持計數(shù)信息通常僅僅用于測試和調(diào)試。比如,假設(shè)不應(yīng)該使用已經(jīng)保持的鎖進入代碼的某一部分。則能夠聲明例如以下:?
class X {ReentrantLock lock = new ReentrantLock();// ... public void m() { assert lock.getHoldCount() == 0;lock.lock();try {// ... method body} finally {lock.unlock();}} }
???? 返回:
???? 當前線程保持此鎖的次數(shù),假設(shè)此鎖未被當前線程保持過。則返回 0
十、死鎖
死鎖會發(fā)生在兩個或者以上的thread在等待兩個或兩個以上的lock被釋放。且程序的環(huán)境卻讓lock永遠無法釋放。十一、Lock公平(Fairness)
? ? ?使用明白的lock時lock應(yīng)該怎樣被授予? ? ? ?1. 讓lock應(yīng)該以先到先服務(wù)的原則被授予。 ? ? ?2. 讓它以可以服務(wù)最多請求的順序來被授予。 ? ? ?3. 鎖應(yīng)該對系統(tǒng)最有利的形式來唄授予。不管它用于什么。(synchronized接近這樣的)版權(quán)聲明:本文博客原創(chuàng)文章,博客,未經(jīng)同意,不得轉(zhuǎn)載。
轉(zhuǎn)載于:https://www.cnblogs.com/hrhguanli/p/4746026.html
總結(jié)
以上是生活随笔為你收集整理的Java 螺纹第三版 第三章数据同步 读书笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈原型模式
- 下一篇: iOS字符串常用用法