java自旋锁
一 Test-and-Set Lock
所谓测试设置是最基本的锁,每个线程共用一把锁,进入临界区之前看没有有线程在临界区,如果没有,则进入,并上锁,如果有则等待。java实践中利用了原子的设置state变量来保证一次只有一个线程可以获得到锁。
public class TASLock implements Lock {
AtomicBoolean state = new AtomicBoolean(false);
@Override
public void lock() {
while (state.getAndSet(true)) {
}
}
@Override
public void unlock() {
state.set(false);
}
}
这种锁优点就是简单,缺点是在硬件层面上读取state时候,如果在cache中命中,那么直接从cache中读取就行。但是没有命中,那么将在总线产生一个广播,如果在其他处理器中的cache中找到该地址,那么就以该地址的值做为响应,并且广播该值。更糟糕的是每一个进入自旋的线程都会产生cache缺失,这样产生大量广播流量,延迟较长。
二 指数后退lock
TASLock如果产生大量自旋的线程,则效率很低,避免这个问题就是给后进入自旋的线程一个延迟避让。避让策略有很多种,这里选择指数回退。
class Backoff {
int max;
int min;
int limit;
public Backoff(int min, int max, int limit) {
this.max = max;
this.min = min;
this.limit = limit;
}
public void backoff() {
int delay = new Random().nextInt(limit);
limit = Math.min(max, 2 * limit);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class BackoffLock implements Lock{
private AtomicBoolean state = new AtomicBoolean(false);
@Override
public void lock() {
Backoff backoff = new Backoff(1000, 5000, 100);
while (true) {
while (state.get()) {};
if (!state.getAndSet(true)) {
return;
} else {
backoff.backoff();
}
}
}
@Override
public void unlock() {
state.set(false);
}
}
三 基于数组的简单队列锁
上面基于TAS的lock并没有真正解决cache缺失的流量问题,所以利用java的ThreadLocal为每一个线程存储一个本地标识索引对应于是否进入临界区而不是在共享的变量上自旋,这样cache流量问题就能得到解决。
public class Alock implements Lock {
ThreadLocal<Integer> mysolitindex = new ThreadLocal<Integer>() {
protected Integer initvalue() {
return 0;
}
};
AtomicInteger tail;
boolean[] flag;
int size;
Alock (int capacity) {
size = capacity;
tail = new AtomicInteger(0);
flag = new boolean[capacity];
flag[0] = true;
}
@Override
public void lock() {
int solt = tail.getAndIncrement() % size;
mysolitindex.set(solt);
while (!flag[solt]) {};
}
}
四 改进的Alock--CLH队列锁
ALock缺点在于并发线程数量固定,空间开销比较大,每次必须分配固定数量的本地线程变量和共享变量。CLHlock解决了空间问题,它利用threadlocal保持2个指针指向pre和current来实现一个隐式的链表,并且通过pre使得cache命中率提高。
class CLHLock implements Lock {
AtomicReference<Qnode> tail;
ThreadLocal<Qnode> myNode
= new Qnode();
public void lock() {
Qnode pred
= tail.getAndSet(myNode);
while (pred.locked) {}
}}
public void unlock() {
myNode.locked.set(false);
myNode = pred;
}
}
class Qnode {
AtomicBoolean locked =
new AtomicBoolean(true);
}
本地线程中保持这指向qnode的指针mynode。如果有L个锁,n个线程,并且每个线程最多同时访问一个锁,那么需要O(L+n)空间。
java自旋锁的更多相关文章
- 自旋锁原理及java自旋锁
一.自旋锁的概念 首先是一种锁,与互斥锁相似,基本作用是用于线程(进程)之间的同步.与普通锁不同的是,一个线程A在获得普通锁后,如果再有线程B试图获取锁,那么这个线程B将会挂起(阻塞):试想下,如果两 ...
- 并发编程--CAS自旋锁
在前两篇博客中我们介绍了并发编程--volatile应用与原理和并发编程--synchronized的实现原理(二),接下来我们介绍一下CAS自旋锁相关的知识. 一.自旋锁提出的背景 由于在多处理器系 ...
- Java锁之自旋锁详解
锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类 ...
- 可重入锁 & 自旋锁 & Java里的AtomicReference和CAS操作 & Linux mutex不可重入
之前还是写过蛮多的关于锁的文章的: http://www.cnblogs.com/charlesblc/p/5994162.html <[转载]Java中的锁机制 synchronized &a ...
- Java并发框架——AQS堵塞队列管理(一)——自旋锁
我们知道一个线程在尝试获取锁失败后将被堵塞并增加等待队列中,它是一个如何的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列. 在谈到CHL Node FIFO队列之前,我们先分析这样 ...
- Java线程并发中常见的锁--自旋锁 偏向锁
随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题.本文着重介绍了在java并发中常见的几种锁机制. 1.偏向锁 偏向锁是JDK1.6提出来的一种锁优化的机制.其核心的思想 ...
- Java并发框架——AQS阻塞队列管理(一)——自旋锁
我们知道一个线程在尝试获取锁失败后将被阻塞并加入等待队列中,它是一个怎样的队列?又是如何管理此队列?这节聊聊CHL Node FIFO队列. 在谈到CHL Node FIFO队列之前,我们先分析这种队 ...
- Java 多线程之自旋锁
一.什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环. 获取锁的线 ...
- Java锁的种类以及辨析(二):自旋锁的其他种类
作者:山鸡 锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具 ...
随机推荐
- angular popover的触发问题;
popover 一般如下用法; <div uib-popover="内容" popover-animation="false" popover-appen ...
- webpack1 新手入门教程
本文github仓库地址: https://github.com/Rynxiao/webpack-tutorial ,里面包括了本教程的所有代码. [如果你觉得这篇文章写得不错,麻烦给本仓库一颗星:- ...
- java 使用spring实现读写分离
最近上线的项目中数据库数据已经临近饱和,最大的一张表数据已经接近3000W,百万数据的表也有几张,项目要求读数据(select)时间不能超过0.05秒,但实际情况已经不符合要求,explain建立索引 ...
- 关于SurfaceView的那些事
今天来说说SurfaceView吧 这东西的特性大家记住一个就行了,它的绘制是在子线程中,所以不堵塞UI,非常适合一些复杂的绘制 SuufaceView有一个重要的对象,是SurfaceHolder, ...
- 2、微信小程序之弹幕的实现(无后台)
对弹幕功能主要利用环信来实现的,读者也许对环信这个东西很陌生,请先自行了解这环信再来看这文章. 环信开发文档:http://docs.easemob.com/im/400webimintegratio ...
- 微信token失效时间
微信token失效时间 为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等,开发者在调用这些 ...
- 关于PHP魔术方法__call的一点小发现
好久没有上博客园写文章了,今晚终于有点空了,就来写一下昨天的一点小发现. 我自己所知,C++,Java的面向对象都有多态的特点,而PHP没有,但PHP可以通过继承链方法的重写来实现多态的属性.而魔术方 ...
- 【MYSQL】SQL 的join 区别
----------------------INNER JOIN--------------------------- 1. 三表联合查询 select XX,XX from a , b , c ...
- Linux基本命令整理_sheng
Linux版本 Linux系统是一个多用户.多任务的分时操作系统. Linux版本分为内核版本和发行版本. 常见的Linux发行版有: RedHat(分为用于企业的Red Hat Enterprise ...
- Stacked Regression的详细步骤和使用注意事项
声明:这篇博文是我基于一篇网络文章翻译的,并结合了自己应用中的一些心得,如果有侵权,请联系本人删除. 最近做推荐的时候,开始接触到Stacking方法,在周志华老师的西瓜书中,Stacking方法是在 ...