多线程间共享数据问题

一、Synchronizedkeyword

     atomic一词与“原子”无关,它以前被觉得是物质的最小的单元,不能再被拆解成更小的部分。
     当一个方法被声明成synchronized,要执行此方法的thread必须先取得一个token,我们将它称为锁。

一旦该方法取得(或者说是获得)锁,它将执行此方法然后释放掉(或者返回)此锁。无论方法时如何返回的(包含通过异常)该锁会被释放。

二、Volatilekeyword

     假设变量被标示为volatile。每次使用该变量时都必须从主寄存器中读出。同样地。每次要写入该变量时,值都必须存入主寄存器。更进一步。Java指定对volatile变量的载入与存储都是atomic的。不管是否是long与double变量。

     volatile声明的变量进行++、--操作不能保证原子性。

     volatile声明的数组,会让数组的引用变成volatile数组中的元素不是volatile。

三、很多其它竞态条件的讨论

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();
}
}
}

     此类共享的数据是由实际的得分数、须要被输入的字母与少数持有的字母来源作为登记用的变量等所组成。解决竞态条件问题意味着让这些数据在正确的scope中被同步化。
     假设newCharacter方法不能确保同步。当中包括的变量char2type、score变量的改动并不能保证在全部的线程中都能实时的获取到正确的最后一次改动的值,导致基于char2type的推断出现故障,接连导致score也出现故障。

     解决的方法是在此类中全部涉及到这两个变量的都把当前类作为同步锁(即每一个方法都加入一个synchronizedkeyword)。目的是在全部线程中调用这些方法都必需要是相互排斥操作,不可能同一时候多个线程调用操作这两个变量的方法,从而保证正确性。

四、显示锁

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();
}
}
}

     与上一个样例原理同样,都是涉及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 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与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 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();
}
}
}
}


     在此样例中,被锁住的对象与用在方法的同步化上的是同一个对象:this对象。     

七、选择Locking机制

     synchronized与Lock在静态方法(static method)上有所差别,由于在方法上使用synchronized是针对当前对象锁定。而静态方法是全局的,使用这样的办法会使确保正确性添加难度,相反使用Lock由于它与当前对象无关。仅仅须要在方法内设置lock与unlock所以更easy确保多线程同步的正确性。

八、Lock Interface


boolean tryLock()

     仅在调用时锁为空暇状态才获取该锁。 

     假设锁可用,则获取锁,并马上返回值 true。

假设锁不可用。则此方法将马上返回值 false。 



     此方法的典型使用语句例如以下: 



      Lock lock = ...;

      if (lock.tryLock()) {

          try {

              // manipulate protected state

          } finally {

              lock.unlock();

          }

      } else {

          // perform alternative actions

      }

     此使用方法可确保假设获取了锁。则会释放锁,假设未获取锁,则不会试图将其释放。

返回:

     假设获取了锁,则返回 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 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锁定是可重入的。即当前声明 synchronized的方法中调用此类的其它 synchronized方法时能够直接进入,无需再次获取锁操作。

     public int getHoldCount()

查询当前线程保持此锁的次数。 

     对于与解除锁操作不匹配的每一个锁操作。线程都会保持一个锁。 



     保持计数信息通常仅仅用于測试和调试。比如,假设不应该使用已经保持的锁进入代码的某一部分。则能够声明例如以下:

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

返回:

     当前线程保持此锁的次数,假设此锁未被当前线程保持过。则返回 0

十、死锁

     死锁会发生在两个或者以上的thread在等待两个或两个以上的lock被释放。且程序的环境却让lock永远无法释放。

十一、Lock公平(Fairness)

使用明白的lock时lock应该怎样被授予?

     1. 让lock应该以先到先服务的原则被授予。
     2. 让它以可以服务最多请求的顺序来被授予。
     3. 锁应该对系统最有利的形式来呗授予。不管它用于什么。(synchronized接近这样的)

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Java 螺纹第三版 第三章数据同步 读书笔记的更多相关文章

  1. Java 线程第三版 第四章 Thread Notification 读书笔记

    一.等待与通知 public final void wait() throws InterruptedException      等待条件的发生. public final void wait(lo ...

  2. Java核心技术卷一基础知识-第7章-图形程序设计-读书笔记

    第7章 图形程序设计 本章内容: * Swing概述 * 创建框架 * 框架定位 * 在组件中显示信息 * 处理2D图形 * 使用颜色 * 文本使用特殊字体 * 显示图像 本章主要讲述如何编写定义屏幕 ...

  3. 《Java并发编程实战》第六章 任务运行 读书笔记

    一. 在线程中运行任务 无限制创建线程的不足 .线程生命周期的开销很高 .资源消耗 .稳定性 二.Executor框架 Executor基于生产者-消费者模式.提交任务的操作相当于生产者.运行任务的线 ...

  4. 《Java并发编程实战》第十三章 显示锁 读书笔记

    一.Lock与 ReentrantLock Lock 提供一种无条件的.可轮询的.定时的.可中断的锁获取操作,全部加锁和解锁的方法都是显式的. public interface Lock { void ...

  5. Java核心技术卷一基础知识-第12章-泛型程序设计-读书笔记

    第12章 泛型程序设计 本章内容: * 为什么要使用泛型程序设计 * 定义简单泛型类 * 泛型方法 * 类型变量的限定 * 泛型代码和虚拟机 * 约束与局限性 * 泛型类型的继承规则 * 通配符类型 ...

  6. < 利用Python进行数据分析 - 第2版 > 第五章 pandas入门 读书笔记

    <利用Python进行数据分析·第2版>第五章 pandas入门--基础对象.操作.规则 python引用.浅拷贝.深拷贝 / 视图.副本 视图=引用 副本=浅拷贝/深拷贝 浅拷贝/深拷贝 ...

  7. Android编程权威指南第三版 第32章

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_35564145/article/de ...

  8. 《TCP/IP详解卷1:协议》第2章 链路层-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  9. 《Java编程思想》——初始化与清理(一)读书笔记

    第一次写这个,这一章都用word写的,结果复制过来没图片....只能上传word文档了.以后改用markdown比较好 word文档地址:<Java编程思想>--初始化与清理(一)读书笔记

随机推荐

  1. C++对C语言的非面向对象特性扩充(1)

    我将分3篇来介绍C++相对于C在非对象特性上的扩充,今天要讲的是C++在注释,输入输出,局部变量说明的扩充,以及const修饰符与C中的#define的比较. 1.C++注释除了包括原有C的块注释/* ...

  2. eclipse导出doc文档

    选中需要导出的项目, 1 点击eclipse上面的Project,选择Generate javadoc..., 2 然后配置 javadoc command,比如我本地的路径为: C:\Program ...

  3. poj 2513

    http://poj.org/problem?id=2513 73348K        1438MS        C++        1614B解题思路:欧拉路的应用 要点 :1.判断连通性   ...

  4. poj 2965

    http://poj.org/problem?id=2965 本题要结合poj 1753 来看最好...又有了一点搜索的经验..加油... #include <iostream> #inc ...

  5. UnixShell编程(第三版)

    这本书相当老了,04年的,现在  在linux上做实验. 1,date 显示日期. 2,who  显示用户,who am i 3,echo 后面字符串会全部输出,,会过滤掉多余空格,单双引号,分号等. ...

  6. openrisc 之 Wishbone总线学习笔记——总线互联

    一,总线命名规范 1,wishbone总线接口信号都是高电平有限 2,wishbone接口信号都是以 _i ,或者是 _o 结束.i表示输入, o表示输出. ()表示该信号为总线信号,总线位宽可以大于 ...

  7. OI不得不知的那些数学定理

    Binomial theorem One can define\[{r \choose k}=\frac{r\,(r-1) \cdots (r-k+1)}{k!} =\frac{(r)_k}{k!}\ ...

  8. 编译:一个 C 程序的艺术之旅(转载)

    C 程序为什么要编译才能执行?一个 C 程序在变成可执行文件的过程中,为什么要经过预处理.编译.汇编.链接这四道工序?让我们从这段简单的 C 程序开始. 为什么要编译 这并不是一个简单的问题.我们知道 ...

  9. Hadoop Security Authentication Terminology --Kerberos

    Hadoop Security Authentication Terminology --Kerberos What is kinit? Kinit -  obtain and cache Kerbe ...

  10. @Autowired与@Resource的差别

    1.@Autowired与@Resource都能够用来装配bean. 都能够写在字段上,或写在setter方法上. 2.@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必 ...