一、锁的劣势

锁定后假设未释放。再次请求锁时会造成堵塞。多线程调度通常遇到堵塞会进行上下文切换,造成很多其它的开销。

在挂起与恢复线程等过程中存在着非常大的开销,而且通常存在着较长时间的中断。
锁可能导致优先级反转,即使较高优先级的线程能够抢先运行,但仍然须要等待锁被释放,从而导致它的优先级会降至低优先级线程的级别。

二、硬件对并发的支持

处理器填写了一些特殊指令,比如:比較并交换、关联载入/条件存储。



1 比較并交换
CAS的含义是:“我觉得V的值应该为A。假设是。那么将V的值更新为B,否则不须要改动告诉V的值实际为多少”。

CAS是一项乐观锁技术。


模拟CAS操作样例:
@ ThreadSafe
public class SimulatedCAS {
@ GuardeBy( "this") private int value ; public synchronized int get(){
return value ;
} public synchronized int compareAndSwap( int expectedValue, int newValue){
int oldValue = value ;
if (oldValue == expectedValue)
value = newValue;
return oldValue;
} public synchronized boolean compareAndSet( int expectedValue, int newValue){
return (expectedValue == compareAndSwap(expectedValue, newValue));
}
}

2 非堵塞的计数器
基于CAS实现的非堵塞计数器
@ ThreadSafe
public class CasCounter {
private SimulatedCAS value ; public int getValue(){
return value .get();
} public int increment(){
int v;
do {
v = value .get();
} while (v != value .compareAndSwap(v, v + 1));
return v + 1;
}
}

CAS的主要缺点是:它将使调度者处理竞争问题(通过重试、回退、放弃),而在使用锁中能自己主动处理竞争问题(线程在获得锁之前将一直堵塞)。


3 JVM对CAS的支持

java.util.concurrent.atomic 类的小工具包,支持在单个变量上解除锁的线程安全编程。

AtomicBoolean 能够用原子方式更新的 boolean 值。
AtomicInteger 能够用原子方式更新的 int 值。
AtomicIntegerArray 能够用原子方式更新其元素的 int 数组。
AtomicIntegerFieldUpdater<T> 基于反射的有用工具,能够对指定类的指定 volatile int 字段进行原子更新。
AtomicLong 能够用原子方式更新的 long 值。 AtomicLongArray 能够用原子方式更新其元素的 long 数组。 AtomicLongFieldUpdater<T> 基于反射的有用工具。能够对指定类的指定 volatile long 字段进行原子更新。
AtomicMarkableReference<V> AtomicMarkableReference 维护带有标记位的对象引用。能够原子方式对其进行更新。
AtomicReference<V> 能够用原子方式更新的对象引用。 AtomicReferenceArray<E> 能够用原子方式更新其元素的对象引用数组。
AtomicReferenceFieldUpdater<T,V> 基于反射的有用工具。能够对指定类的指定 volatile 字段进行原子更新。
AtomicStampedReference<V> AtomicStampedReference 维护带有整数“标志”的对象引用,能够用原子方式对其进行更新。

三、原子变量类

1 原子变量是一种“更好的volatile”

通过CAS来维持包括多个变量的不变性条件样例:
import java.util.concurrent.atomic.AtomicReference;

public class CasNumberRange {
private static class IntPair{
final int lower ; // 不变性条件: lower <= upper
final int upper ; public IntPair( int lower, int upper) {
this .lower = lower;
this .upper = upper;
}
} private final AtomicReference<IntPair> values =
new AtomicReference<IntPair>( new IntPair(0, 0)); public int getLower(){
return values .get(). lower;
} public int getUpper(){
return values .get(). upper;
} public void setLower( int i){
while (true ){
IntPair oldv = values .get();
if (i > oldv.upper ){
throw new IllegalArgumentException( "Cant't set lower to " + i + " > upper");
}
IntPair newv = new IntPair(i, oldv.upper );
if (values .compareAndSet(oldv, newv)){
return ;
}
}
}
// 对setUpper採用相似的方法
}



2 性能比較:锁与原子变量

使用ReentrantLock、AtomicInteger、ThreadLocal比較,通常情况下效率排序是ThreadLocal > AtomicInteger > ReentrantLock。

四、非堵塞算法

1 非堵塞的栈

import java.util.concurrent.atomic.AtomicReference;

public class ConcurrentStack<E> {
private AtomicReference<Node<E>> top = new AtomicReference<ConcurrentStack.Node<E>>(); public void push(E item){
Node<E> newHead = new Node<E>(item);
Node<E> oldHead; do {
oldHead = top .get();
newHead. next = oldHead;
} while (!top .compareAndSet(oldHead, newHead));
} public E pop(){
Node<E> oldHead;
Node<E> newHead;
do {
oldHead = top .get();
if (oldHead == null) {
return null ;
}
newHead = oldHead. next ;
} while (!top .compareAndSet(oldHead, newHead));
return oldHead.item ;
} private static class Node<E>{
public final E item;
public Node<E> next ; public Node(E item){
this .item = item;
}
}
}



2 非堵塞的链表
CAS基本使用模式:在更新某个值时存在不确定性,以及在更新失败时又一次尝试。
import java.util.concurrent.atomic.AtomicReference;

@ ThreadSafe
public class LinkedQueue<E> {
private static class Node<E>{
final E item;
final AtomicReference<Node<E>> next; public Node(E item, Node<E> next){
this .item = item;
this .next = new AtomicReference<Node<E>>(next);
}
} private final Node<E> dummy = new Node<E>( null , null );
private final AtomicReference<Node<E>> head =
new AtomicReference<Node<E>>(dummy);
private final AtomicReference<Node<E>> tail =
new AtomicReference<Node<E>>(dummy); public boolean put(E item){
Node<E> newNode = new Node<E>(item, null);
while (true ){
Node<E> curTail = tail.get();
Node<E> tailNext = curTail.next.get();
if (curTail == tail.get()){
if (tailNext != null){
// 队列处于中间状态,推进尾节点
tail.compareAndSet(curTail, tailNext);
} else {
// 处于稳定状态, 尝试插入新节点
if (curTail.next.compareAndSet( null, newNode)){
// 插入操作成功,尝试推进尾节点
tail.compareAndSet(curTail, tailNext);
return true ;
}
}
}
}
}
}



3 原子的域更新器
原子的域更新器类表示有volatile域的一种基于反射的“视图”,从而可以在已有的volatile域上使用CAS
private static class Node<E>{
private final E item;
private volatile Node<E> next; public Node(E item){
this.item = item;
}
} private static AtomicReferenceFieldUpdater<Node, Node> nextUpdater
= AtomicReferenceFieldUpdater.newUpdater(Node.class , Node.class , "next" );



4 ABA问题
处理V的值首先由A变成B。再由B变成A的问题。


《Java并发编程实战》第十五章 原子变量与非堵塞同步机制 读书笔记的更多相关文章

  1. java并发编程实战:第十五章----原子变量与非阻塞机制

    非阻塞算法:使用底层的原子机器指令(例如比较并交换指令)代替锁来确保数据在并发访问中的一致性 应用于在操作系统和JVM中实现线程 / 进程调度机制.垃圾回收机制以及锁和其他并发数据结构 可伸缩性和活跃 ...

  2. 《Java并发编程实战》第五章 同步容器类 读书笔记

    一.同步容器类 1. 同步容器类的问题 线程容器类都是线程安全的.可是当在其上进行符合操作则须要而外加锁保护其安全性. 常见符合操作包括: . 迭代 . 跳转(依据指定顺序找到当前元素的下一个元素) ...

  3. Java并发编程实战 第15章 原子变量和非阻塞同步机制

    非阻塞的同步机制 简单的说,那就是又要实现同步,又不使用锁. 与基于锁的方案相比,非阻塞算法的实现要麻烦的多,但是它的可伸缩性和活跃性上拥有巨大的优势. 实现非阻塞算法的常见方法就是使用volatil ...

  4. java并发编程实战:第五章----基础构建模块

    委托是创建线程安全类的一个最有效的策略:只需让现有的线程安全类管理所有的状态即可. 一.同步容器类 1.同步容器类的问题 同步容器类都是线程安全的,容器本身内置的复合操作能够保证原子性,但是当在其上进 ...

  5. 【java并发编程实战】第五章:基础构建模块

    1.同步容器类 它们是线程安全的 1.1 vector和hashtable. 和Collections.synchronizeXxx()一样.实现方式就是在每个方法里面加入synchronize代码块 ...

  6. 《Java并发编程实战》第三章 对象的共享 读书笔记

    一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见 ...

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

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

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

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

  9. 《Java并发编程实战》第七章 取消与关闭 读书笔记

        Java没有提供不论什么机制来安全地(抢占式方法)终止线程,尽管Thread.stop和suspend等方法提供了这种机制,可是因为存在着一些严重的缺陷,因此应该避免使用. 但它提供了中断In ...

随机推荐

  1. 8款必备的免费移动Web开发框架(HTML5/JS)

    标签:JavaScript HTML5 移动开发 Web开发 jQuery 应用程序框架 插件 概述:随着智能手机和平板电脑的普及,移动开发逐渐成为众多开发者追逐的潮流.拥有一款优秀的移动Web开发框 ...

  2. hdu4638Group

    http://acm.hdu.edu.cn/showproblem.php?pid=4638 求某一区间所包含的连续的段 对于乱序的数 到了i这个数所包含的段数 首先把这个数看作单独的段 再看一下前面 ...

  3. ECSHOP:首页实现显示子分类商品,并实现点击Tab页切换分类商品

    例子:首页实现显示子分类商品,并实现点击Tab页切换分类商品(非AJAX) 开始:    1. 打开调试开关     文件地址:include/cls_template.php 找到 : functi ...

  4. 在PowerDesigner中设计物理模型2——约束

    唯一约束 唯一约束与创建唯一索引基本上是一回事,因为在创建唯一约束的时候,系统会创建对应的一个唯一索引,通过唯一索引来实现约束.不过唯一约束更直观的表达了对应列的唯一性,使得对应索引的目的更加清晰,所 ...

  5. 无法找到.exe的调试信息

    原文:无法找到.exe的调试信息 前天重装了电脑,并配置了Visual Studio2005的VC正则库,boost/regex,运行速度马上快了三倍吧,到底是怎么快的,我还真说不清楚,因为电脑这玩意 ...

  6. 【C/C++运行时库】 /MT /MTd /MD /MDd对C/C++运行库的影响

    欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3146937.html 测试VS中[项目属性]-[C/C++]-[代码生成]选项中的[运行库]- [ /MT, ...

  7. [原]Links

    [Date]2014-04-19 [Author]wintys (wintys@gmail.com) http://wintys.cnblogs.com [Content]: 1.Android 1. ...

  8. bzoj 1037 [ZJOI2008]生日聚会Party(DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1037 [题意] 一排n男m女,求满足任意连续段男女人数之差不超过k的数目. [思路] ...

  9. 笔记:1.css样式,最前边加 @charset "utf-8";是为什么2.js判断各种浏览器的方法

    表明CSS文件的页面编码为UTF-8..如果这个CSS的文件编码也是UTF-8的话..那么在浏览器中看到的CSS文件的页面中中文的注释或者中文字体就可以正确显示为中文,如果CSS的文件编码和页面不一致 ...

  10. centos7 rabbitmq系统部署

    CentOS7 1.安装系统 基础设施服务器:Java平台.Linux远程管理.开发工具 2.打开网络连接: (1)cd  /etc/sysconfig/network-scripts/  #进入网络 ...