多线程间共享数据问题

一、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. IOS数据本地存储的四种方式--

    注:借鉴于:http://blog.csdn.net/jianjianyuer/article/details/8556024 在IOS开发过程中,不管是做什么应用,都会碰到数据保存问题.将数据保存到 ...

  2. Sphnix

    Sphinx高性能的搜索引擎(简单.强大.实用) http://blog.csdn.net/lgm252008/article/details/5373354

  3. linux基础随笔

    磁盘管理 sda s:磁盘接口的类型(sata scsci sas) d:驱动器(drive) a:(第一块磁盘,同理b第二块磁盘)hda h:ide接口 第一块磁盘的第一个分区:sda1 mount ...

  4. php 用户访问菜单页面,必须登录,判断用户是否登录

    <pre name="code" class="python"># 本节课大纲: 一.空模块和空操作 1.空操作 function _empty($ ...

  5. Muduo 网络编程示例之零:前言

    陈硕 (giantchen_AT_gmail)Blog.csdn.net/Solstice Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category/ ...

  6. Java怎样高速构造JSON字符串

    目标:依据key/value高速构造一个JSON字符串作为參数提交到web REST API服务上. 分别測试里阿里巴巴的FastJson和Google Gson,终于我採用了Google Gson来 ...

  7. 注解配置 ssh

    注解 <?xml version="1.0" encoding="UTF-8"? > <beans xmlns="http://ww ...

  8. SQL Server 2008 还原数据库

    1.得到数据库备份文件,怎么得到的,[能够看这里]~ 2.把备份文件加个.bak 的后缀,比如: 3.打开SQL , 你能够新建一个空数据库 , 或者利用原有的数据库 , 点击右键>>任务 ...

  9. [计算机网络] vsftpd的安装与使用

    简单介绍: vsftpd是一个能够执行在类UNIX操作系统上的FTPserver软件,它能够执行在Linux.BSD.Solaris.HP-UX等系统上. 1 vsftpd的安装 在ubuntu系统上 ...

  10. iOS 开发 Message Digest Algorithm 5(MD5加密)

    MD5的全称是Message Digest Algorithm 5(消息摘要算法第五版),是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.在90年代初由MIT Laboratory ...