多线程间共享数据问题

一、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. PHPExcel 生成图形报表

    db.php为数据库操作类, $config为数据库配置,PHPExcel版本为PHPExcel_1.8.0,  PHP代码: $dir = dirname(__FILE__); require $d ...

  2. java-输出格式

    https://docs.oracle.com/javase/tutorial/java/data/numberformat.html Formatting Numeric Print Output ...

  3. poj 1715 Hexadecimal Numbers 排列组合

    /** 大意: 给定16进制数的16个字母,,求第k大的数,,要求数的长度最大为8.,并且每个数互不相同. 思路: 从高到低挨个枚举,每一位能组成的排列数 ,拿最高位来说,能做成的排列数为15*A(1 ...

  4. WebService开发实例(Axis2实现,无需安装,快速实现)

    曾经做过的项目里涉及Android客户端向服务器发送请求,服务器访问数据库获得数据并返回给Android客户端.当时Android客户端与服务器的通信已经实现,我只负责客户端布局和数据呈现的部分,近日 ...

  5. hpuoj回文串问题(manacher+kmp)

    1699: 回文串问题 时间限制: 1 Sec  内存限制: 128 MB 提交: 22  解决: 3 [提交][状态][讨论版] 题目描述 还是回文串问题,字符串是啥,大家应该都知道,就是满足 S[ ...

  6. Android经常使用UI组件 - TextView

    TextView是Android里面用的最多的UI组件,一般使用在须要显示一些信息的时候,其不能输入,仅仅能初始设定或者在程序中改动. 实例:TextViewDemo 执行效果: 代码清单: 布局文件 ...

  7. English learning method ---学英语重中之重打通“任督二脉”

    漫漫十年艰辛路,英语学习之旅 曾经秉承“路漫漫其修远兮,吾将上下而求索”的信念,初一那年了解到原来(a b c d e f g) 不仅仅读作(啊,波,词,的,额,佛,哥),在英语的世界中它有另外的读法 ...

  8. ThinkPHP - 自定义标签库 - 标签驱动

    ThinkPHP 官方文档:http://document.thinkphp.cn/manual_3_2/taglib_driver.html 创建一个类,继承自TagLib类: <?php / ...

  9. python求微分方程组的数值解曲线01

    本人最近在写一篇关于神经网络同步的文章,其一部分模型为: x_i^{\Delta}(t)= -a_i*x_i(t)+ b_i* f(x_i(t))+ \sum\limits_{j \in\{i-1, ...

  10. C++,对象成员的访问

    成员变量和成员函数的访问可以采用以下几种访问方式:对象.成员变量名: 对象.成员函数名(实参列表)对象的指针->成员变量名; 对象的指针->成员函数名(实参列表)对象的引用.成员变量名对象 ...