一、能避免同步吗?

取得锁会由于下面原因导致成本非常高:

    取得由竞争的锁须要在虚拟机的层面上执行很多其它的程序代码。

    要取得有竞争锁的线程总是必须等到锁被释放后。

1. 寄存器的效应

计算机有一定数量的主寄存器用来存储与程序有关的数据。

从逻辑上的观点来看,每一个Thread都有自己的一组寄存器。当操作系统将某个Thread分配给CPU时,它会把该Thread特有的信息载入到CPU的寄存器中。

在分配不同的Thread给CPU之前,它会将寄存器的信息存下来。

所以Thread间绝不会共享保存在寄存器的数据。

当虚拟机进入synchronized方法或者块时。它必须又一次载入本来已经缓存到自有寄存器上的数据。在虚拟机离开synchroized方法或者块之前,它必须把自有寄存器存入主寄存器中。

2. 重排语句的效应

在单独线程中。程序总是依照代码一行行的运行的。可是假设是多个线程并发,Java并不保证每一个线程run方法的运行顺序,也就是可能当中一个线程运行到一半就会被临时停止。运行其它线程,之后再切换回来。

多个线程间调度运行的无序性就是重排语句的效应。

3. 双重检查的Locking

二、Atomic变量

1. Atomic Class的概述

AtomicInteger, AtomicLong, AtomicBoolean, AtomicRefrences。Atomic的功能实现时通过使用use-level的Java程序无法訪问的固有方法来完毕的。

atomic package支持更复杂的变量类型吗?

一些不支持。比如字符或者浮点。

    AtomicStampedReference可以让mark或stamp跟在不论什么对象的引用上。

    AtomicMarkableReference提供一个包括对象引用结合boolean的数据结构。

2. 使用Atomic Class

import javax.swing.*;
import java.awt.event.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import javathreads.examples.ch05.*; public class ScoreLabel extends JLabel implements CharacterListener {
private AtomicInteger score = new AtomicInteger(0);
private AtomicInteger char2type = new AtomicInteger(-1);
private AtomicReference<CharacterSource> generator = null;
private AtomicReference<CharacterSource> typist = null; public ScoreLabel (CharacterSource generator, CharacterSource typist) {
this.generator = new AtomicReference(generator);
this.typist = new AtomicReference(typist); if (generator != null)
generator.addCharacterListener(this);
if (typist != null)
typist.addCharacterListener(this);
} public ScoreLabel () {
this(null, null);
} public void resetGenerator(CharacterSource newGenerator) {
CharacterSource oldGenerator; if (newGenerator != null)
newGenerator.addCharacterListener(this); oldGenerator = generator.getAndSet(newGenerator);
if (oldGenerator != null)
oldGenerator.removeCharacterListener(this);
} public void resetTypist(CharacterSource newTypist) {
CharacterSource oldTypist; if (newTypist != null)
newTypist.addCharacterListener(this); oldTypist = typist.getAndSet(newTypist);
if (oldTypist != null)
oldTypist.removeCharacterListener(this);
} public void resetScore() {
score.set(0);
char2type.set(-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.get()));
}
});
} public void newCharacter(CharacterEvent ce) {
int oldChar2type; // Previous character not typed correctly - 1 point penalty
if (ce.source == generator.get()) {
oldChar2type = char2type.getAndSet(ce.character); if (oldChar2type != -1) {
score.decrementAndGet();
setScore();
}
}
// If character is extraneous - 1 point penalty
// If character does not match - 1 point penalty
else if (ce.source == typist.get()) {
while (true) {
oldChar2type = char2type.get(); if (oldChar2type != ce.character) {
score.decrementAndGet();
break;
} else if (char2type.compareAndSet(oldChar2type, -1)) {
score.incrementAndGet();
break;
}
} setScore();
}
}
}

变量替换

score与char2type变量已经改成atomic变量。

以上resetScroe方法中对两个变量进行改动。尽管使用atomic能保证每一个变量的原子性,可是假设多个线程同一时候运行resetScore方法依旧会出现竞态条件。

有可能一个线程运行resetScore的第一行代码score.set(0);还未运行第二行,而另外一个线程可能已经运行newCharacter方法获取char2type的值,可是之前的线程运行resetScore方法还未对char2type进行改动。由于resetScore整个方法并非原子的。





变更算法

resetGenerator与resetTypist两个方法,以resetGenerator方法为例,将generator变量变成AtomicRerence相同引发上面描写叙述的问题。

通知与Atomic变量

import java.awt.*;
import javax.swing.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import javathreads.examples.ch05.*;

public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable {

private AtomicBoolean done = new AtomicBoolean(true);
private AtomicInteger curX = new AtomicInteger(0);
private AtomicInteger tempChar = new AtomicInteger(0);
private Thread timer = null;

public AnimatedCharacterDisplayCanvas() {
startAnimationThread();
}

public AnimatedCharacterDisplayCanvas(CharacterSource cs) {
super(cs);
startAnimationThread();
}

private void startAnimationThread() {
if (timer == null) {
timer = new Thread(this);
timer.start();
}
}

public void newCharacter(CharacterEvent ce) {
curX.set(0);
tempChar.set(ce.character);
repaint();
}

protected void paintComponent(Graphics gc) {
char[] localTmpChar = new char[1];
localTmpChar[0] = (char) tempChar.get();
int localCurX = curX.get();

Dimension d = getSize();
int charWidth = fm.charWidth(localTmpChar[0]);
gc.clearRect(0, 0, d.width, d.height);
if (localTmpChar[0] == 0)

Java 线程第三版 第五章 极简同步技巧 读书笔记的更多相关文章

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

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

  2. Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

    第一章 Thread导论 为何要用Thread ? 非堵塞I/O      I/O多路技术      轮询(polling)      信号 警告(Alarm)和定时器(Timer) 独立的任务(Ta ...

  3. Java 线程第三版 第九章 Thread调度 读书笔记

    一.Thread调度的概述 import java.util.*; import java.text.*; public class Task implements Runnable { long n ...

  4. Java 线程第三版 第八章 Thread与Collection Class 读书笔记

        JDK1.2引入最有争议性的改变是将集合类默觉得不是Thread安全性的. 一.Collection Class的概述 1. 具有Threadsafe 的Collection Class: j ...

  5. 光源 材质 简析——基于《real time rendering》第三版 第五章

    对于真是世界的渲染,有三个重要的组成部分,光源,材质,以及摄像机.下面,我们一个一个来简单介绍一下. 光源:方向光,点光源,聚光灯.但是,在和物体表面交互的时候,光源对物体表面的影响是依赖光的辐照度( ...

  6. 《Java并发编程实战》第十一章 性能与可伸缩性 读书笔记

    造成开销的操作包含: 1. 线程之间的协调(比如:锁.触发信号以及内存同步等) 2. 添加�的上下文切换 3. 线程的创建和销毁 4. 线程的调度 一.对性能的思考 1 性能与可伸缩性 执行速度涉及下 ...

  7. Javascript模式(第五章对象创建模式)------读书笔记

    一 命名空间模式 1 命名空间模式的代码格式 var MYAPP={ name:"", version:"1.0", init:function(){ } }; ...

  8. 《CLR.via.C#第三版》第二部分第13章节 接口 读书笔记(七)

    这章的书写感觉很普通,是些基础的认知知识. 其中一点的重要认知,泛型接口的好处(其实也是使用泛型的好处之一):编译时类型安全&处理值类型时减少装箱. 再说点书上没有的.本来这些知识我打算另外分 ...

  9. 《CLR.via.C#第三版》第二部分第12章节 泛型 读书笔记(六)

    终于讲到泛型了.当初看到这个书名,最想看的就是作者对泛型,委托,反射这些概念的理解.很多人对泛型的理解停留在泛型集合上,刚开始我也是,随着项目越做越多,对待泛型的认识也越来越深刻. 泛型的概念:泛型是 ...

随机推荐

  1. php读写文件要加锁

    http://www.bubuko.com/infodetail-241753.html

  2. jQuery 之 验证表单

    简单的东西重复做,做多了之后,才能说熟能生巧. 做好一个精美的页面,固然是好,但是,一个页面除了写好之外,我们更需要的是将其功能完善.比如表单的验证,这只是众多工作之一.然后本次就以jQuery的va ...

  3. shell变量的数值计算

    shell中常见的算术运算命令如下 1.(())  用于整数运算的常用运算符,效率很高 2.let 用于整数运算,类似于  (()) 3.expr  可用于整数计算,但还有很多其他的额外功能 4.bc ...

  4. MFC 禁用输入法

    #include <Imm.h> HIMC m_hImc; // 全局或者成员变量 // Function for Disabling IME void CMyDialog::Disabl ...

  5. 30+ Excellent Windows Phone 7 Development Tutorials

    原文发布时间为:2012-01-16 -- 来源于本人的百度文章 [由搬家工具导入] Here are 30+ cool Windows Phone Development articles for ...

  6. js Regex match, exec, test & jquery plugin, visit the official website!

    http://plugins.jquery.com/?s=bootstrap 1. /reg/.test(strval) 2."strval".match(/reg/g), a r ...

  7. .net连接mysql

    首先在官网下载,mysql-connect-net,用于使用mysql的驱动程序,我在下载mysql-connect-net.msi. installer后,执行安装程序的时候一直无法安装成功,最简单 ...

  8. FTK应用程序编程接口(API)手册-1【转】

    转自:http://blog.csdn.net/absurd/article/details/6702047 框架函数 框架函数支撑FTK的主体,它负责初始化应用程序,启动主循环和退出主循环.它对任何 ...

  9. 知乎上的一些文章---leetcode【笔记1】

    张土汪 http://github.com/shawnfan Java{script}代码仔 42 人赞同 [1.19.2017] 更新: 2017年1月17日, 陪我征战多年的 2014 MackB ...

  10. linux 共享内存 信号量 同步

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...