- 浏览: 532421 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
c__海棠依旧:
很强,对于我这个新手很容易理解,准们登录来给你点赞的!
BeanFactory和FactoryBean -
hudazheng:
很清晰!
X86、X64和X86_64区别 -
hugh.wang:
...
BeanFactory和FactoryBean -
CB00J:
...
Executor框架和线程池 -
Arbow:
请教一个问题。现在互联网业务的数据库通常用分片方式来连接一组数 ...
BoneCP源码——概述
锁的劣势
Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程持有守护变量的锁,都采用独占的方式来访问这些变量,如果出现多个线程同时访问锁,那第一些线线程将被挂起,当线程恢复执行时,必须等待其它线程执行完他们的时间片以后才能被调度执行,在挂起和恢复执行过程中存在着很大的开销。锁还存在着其它一些缺点,当一个线程正在等待锁时,它不能做任何事。如果一个线程在持有锁的情况下被延迟执行,那么所有需要这个锁的线程都无法执行下去。如果被阻塞的线程优先级高,而持有锁的线程优先级低,将会导致优先级反转(Priority Inversion)。
volatile的优势
与锁相比,volatile变量是一和更轻量级的同步机制,因为在使用这些变量时不会发生上下文切换和线程调度等操作,但是volatile变量也存在一些局限:不能用于构建原子的复合操作,因此当一个变量依赖旧值时就不能使用volatile变量
悲观锁和乐观锁
独占锁是一种悲观锁,synchronized就是一种独占锁,它假设最坏的情况,并且只有在确保其它线程不会造成干扰的情况下执行,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
CAS操作
Compare and Swap,比较并操作,CPU指令,在大多数处理器架构,包括IA32、Space中采用的都是CAS指令,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”,CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
JVM对CAS的支持
在JDK1.5之前,如果不编写明确的代码就无法执行CAS操作,在JDK1.5中引入了底层的支持,在int、long和对象的引用等类型上都公开了CAS的操作,并且JVM把它们编译为底层硬件提供的最有效的方法,在运行CAS的平台上,运行时把它们编译为相应的机器指令,如果处理器不支持CAS指令,那么JVM将使用自旋锁。在原子类变量中,如java.util.concurrent.atomic中的AtomicXXX,都使用了这些底层的JVM支持为数字类型的引用类型提供一种高效的CAS操作,而在java.util.concurrent中的大多数类在实现时都直接或间接的使用了这些原子变量类。
下面代码说明了CAS的语义(并不是真正的实现,CAS的实现是调用native方法):
/** * Huisou.com Inc. * Copyright (c) 2011-2012 All Rights Reserved. */ package thread; import org.apache.http.annotation.GuardedBy; import org.apache.http.annotation.ThreadSafe; /** * @description * * @author chenzehe * @email hljuczh@163.com * @create 2013-1-6 上午09:02:47 */ @ThreadSafe public class SimulatedCAS { @GuardedBy("this") private int value; public synchronized int get() { return value; } public synchronized int comparedAndSwap(int expectedValue, int newValue) { int oldValue = value; if (oldValue == expectedValue) { value = newValue; } return oldValue; } public synchronized boolean compareAndSet(int expectedValue, int newValue) { return (expectedValue == comparedAndSwap(expectedValue, newValue)); } }
下面代码演示了非阻塞计数器:
/** * Huisou.com Inc. * Copyright (c) 2011-2012 All Rights Reserved. */ package thread; /** * @description * * @author chenzehe * @email hljuczh@163.com * @create 2013-1-6 上午09:48:52 */ public class CasCounnter { private SimulatedCAS value; public int getValue() { return value.get(); } public int increment() { int v; do { v = value.get(); } while (v != value.comparedAndSwap(v, v + 1)); return v + 1; } }
AtomicInteger中实现自增的代码为:
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } } public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
表面上看起来,基于CAS的计数器似乎比基于锁的计数器在性能上更差一些,因为它还要执行更多的操作和更复杂的控制流,并且还依赖看似复杂的CAS操作,实际上,当竞争程度不高时,基于CAS的计数器在性能上远远超过了基于锁的计数器,而在没有竞争时甚至更高,如果要快速获取无竞争的锁,那么至少需要一次CAS操作加上与其它锁相关的操作,因此基于锁的计数即使在最好的情况下也会比基于CAS的计数器在一般情况下执行更多的操作。由于CAS在大多数情况下都能执行成功,因此硬件能够正确的预测while循环中的分支,从而把控制逻辑的开锁降到最低。
锁与原子变量的性能比较
在高度竞争的情况下,锁的性能将超过原子变量的性能,但在更真实的竞争情况下,原子变量的性能将超过锁的性能,这是因为锁在发竞争时会挂起线程,从而降低了CPU的使用率和共享内存总线上的同步通信量,另一方面,如果使用原子变量,那么发出调用的类负责对竞争进行管理,在遇到竞争时立即重试,这通常是种正确的做法,但是在竞争激烈环境下会导致更多的竞争。在实际的情况中,任何一个程序都不会除了竞争锁或原子变量而什么事都不做,不会达到很高的竞争,所以在更常见的情况下,原子变量的效率会更高,在可伸缩性上要高于锁。
非阻塞算法
如果在某个算法中,一个线程的失败或挂起不会引起其它线程也失败或挂起,那么这个算法就被称为非阻塞算法;如果在算法的每个步骤中都存在每个线程能够执行下去,那么这种算法称为无锁算法(Lock-Free)。如果在算法中仅将CAS用于协调线程之间的操作,并且能正确的实现,那么它即是一种非阻塞算法,也是一种无锁算法。在非阻塞算法中通常不会出现死锁和优先级反转问题,但可能出现饥饿和活锁问题,因为在算法中会反复的重试。
下面代码为非阻塞的栈(使用Treiber算法):
package thread; import java.util.concurrent.atomic.AtomicReference; public class ConcurrentStack<T> { private AtomicReference<Node<T>> stacks = new AtomicReference<Node<T>>(); public T push(T e) { Node<T> oldNode, newNode; for (;;) { // 这里的处理非常的特别,也是必须如此的。 oldNode = stacks.get(); newNode = new Node<T>(e, oldNode); if (stacks.compareAndSet(oldNode, newNode)) { return e; } } } public T pop() { Node<T> oldNode, newNode; do{ oldNode = stacks.get(); if(oldNode==null){ return null; } newNode = oldNode.next; }while(!stacks.compareAndSet(oldNode, newNode)); return oldNode.object; } private static final class Node<T> { private T object; private Node<T> next; private Node(T object, Node<T> next) { this.object = object; this.next = next; } } }
ABA问题
如果在算法中的节点可以被循环使用,那么在使用CAS指令时就会出现这种问题,主要指在没有垃圾回收机制的环境中,在CAS操作中,在更新之前先判断V的值是否仍然A,如果是的话就继续执行更新操作,但是有的时候还需要知道“自从上次看到V的值为A以后,这个值是否发生了变化?”,在某些算法中,如果V的值先由A变成B,再由B变成A,那么仍然认为是发生了变化,并需要重新执行算法中的步骤。在这种情况下,即使链表的头节点仍然指向之前观察到的节点,但也不足以说明链表的内容没有变化。如果通过垃圾回收机制仍然无法避免ABA问题,那么还有下面简单方案:不是更新某个引用的值,而是更新两个值,包括一个引用和一个版本号,即使这个值由A变为B,然后为变为A,版本号也是不同的。AtomicStampedReference和AtomicMarkableReference支持在两个变量上执行原子的条件更新。AtomicStampedReference更新一个“对象-引用”二元组,通过在引用上加上“版本号”,从而避免ABA问题,AtomicMarkableReference将更新一个“对象引用-布尔值”的二元组。
发表评论
-
Java异常机制Error类和Exception类
2015-01-23 20:39 0Error类和Exception类都继承自Throwabl ... -
RPC框架简单实现
2014-11-24 21:47 1437/* * Copyright 2011 A ... -
Java读取文件中单词进行排序并写到另一个文件中
2013-12-04 11:12 4707支持 http://ifeve.com/tao-code-m ... -
Java级联调用方法的类设计
2013-11-13 14:10 3170在Java方法设计时返回当前对象的引用(thi ... -
用反射解析jar文件并执行里面Java代码
2013-10-30 23:25 114181、使用JarFile类读取jar包MANIFEST.MF ... -
Hadoop IPC RPC类中对请求的客户端缓存类ClientCache问题
2013-09-24 19:52 2023Hadoop IPC RPC类中对请求的客 ... -
Java NIO 使用实例
2013-09-23 20:47 7035在JDK1.4之前,Java Output ... -
Java 远程接口调用 RMI
2013-09-06 12:00 0Java RMI 指的是远程方法调用 (Remo ... -
Comparable Comparator 的区别
2013-09-03 14:34 1208注:本文为转载 当需要排序的集合或数组不是单纯的数字型时 ... -
Java 枚举使用实例
2013-07-01 15:30 1929Lucene Field类中使用枚举如下: 声明抽象方法 ... -
BoneCP源码——BoneCP中使用的第三方包 jsr166y、 LinkedTransferQueue队列、fork-join框架
2013-03-18 19:06 3400BoneCP主要使用了 ... -
redis 集群系统
2013-03-15 10:59 0redis 集群系统 -
BoneCP源码——BoneCP中使用的多线程
2013-03-16 17:53 39031、asyncExecutor 可缓存线程池,用于异步的创建 ... -
面试题——在一个文本里有N多个数据,使用多线程最快求和
2013-03-08 13:51 5393思路:把所有数据分组,每组使用一个线程去计算结果,计算完后 ... -
面试题——在多线程环境下如何保证一个List集合中的元素不超过15个
2013-02-22 19:16 4937这是有一次去面试被问到的,当时只知道用synchroniz ... -
阻塞队列BlockingQueue
2013-02-04 15:16 16861、队列Queue介绍 Queue是JDK1.5引入的接 ... -
Java 并发集合ConcurrentHashMap
2013-02-01 18:00 3524ConcurrentHashMap是JDK1.5并发包中提 ... -
Java 并发集合CopyOnWriteArrayList
2013-01-30 21:22 35461、Java在JDK1.5之前基本上对所有集合都实现了线程 ... -
Java集合框架 Map接口
2013-01-30 18:34 15861、HashMap HashMap是Map接口最常见的实 ... -
Java集合框架 Collection接口
2013-01-29 17:49 11621、ArrayList ArrayList是List接口 ...
相关推荐
主要介绍了Java并发编程之原子变量与非阻塞同步机制,本文讲解了非阻塞算法、悲观技术、乐观技术、CAS操作、原子变量、性能比较:锁与原子变量等内容,需要的朋友可以参考下
现代的处理器都包含对并发的支持,其中最通用的方法就是比较并交换(compare and swap),简称CAS。下面我们来一起学习一下吧
第15章 原子变量与非阻塞同步机制261 15.1 锁的劣势261 15.2 硬件对并发的支持262 15.2.1 比较并交换263 15.2.2 非阻塞的计数器264 15.2.3 JVM对CAS的支持265 15.3 原子变量类265 15.3.1 原子变量是一种“更...
同步非阻塞 基于信号 多路复用 异步IO 类加载机制 双亲委派 OSGI 算法 搜索 二分 排序 选择 冒泡 插入 快速 归并 堆 桶 基数 常用算法 贪婪 回溯 剪枝 动态规划 数据挖掘算法 KMP算法 ...
Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...