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