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等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具 ...
随机推荐
- 自己编写的 C++ 超轻量级日志类
[自己编写的 C++ 超轻量级日志类(兼容vc++6.0.vs2010.vs2015)] 先来看效果: [测试文件:test.cpp] /* 作者:闫文山 时间:2017/07/02 介绍: 本日志类 ...
- WdatePicker文本框显示当前日期和时间限制<My97DatePicker两个日期范围不超过30天,第一个小于第二个,都不大于当前日期 >
My97DatePicker是很不错的一个日期选择插件,体积只有几十k但是功能非常强大.官网:http://www.my97.net/ 能满足很多苛刻的要求. WdatePicker文本框显示当前日期 ...
- CentOS 下搭建FTP服务器
vsftpd是Linux下比较著名的FTP服务器,搭建FTP服务器当然首选这个.本文介绍了在CentOS 6 4下安装vsftpd.配置虚拟用户登录FTP的过程.正 vsftpd是Linux下比较著名 ...
- VIM基础知识整理(附思维导图)
这是当时初学VIM后做的一个思维导图,图片稍大,所以从freemind导出了html文本po在下面:图片在最下方,放大可清晰浏览. VIM 普通模式 普通编辑命令 功能:浏览,普通编辑 x:删除光标所 ...
- JanaScript数据类型
数据类型 一.基础类型值包括:undefined.null.boolean.string.number 基础类型分别在内存中占有大小空间,它们的值保存在栈空间,我们通过按值来访问. undefined ...
- CharacterEncodingFilter -处理字符格式
package com.pb.news.web.filter; import java.io.IOException;import javax.servlet.Filter;import javax. ...
- 关于Net开发中一些SQLServer性能优化的建议
一. ExecuteNonQuery和ExecuteScalar 对数据的更新不需要返回结果集,建议使用ExecuteNonQuery.由于不返回结果集可省掉网络数据传输.它仅仅返回受影响的行数.如果 ...
- CSS使用心得小结
CSS心得 最近对CSS的使用有一些小心得,在此写下来给大家分享分享 .最后附上选择器的实例代码. ------DanlV CSS是什么 层叠样式表(英文全称:Cascading Style Shee ...
- Java探秘之神秘的字符串String(二)
不可变性 String可以说是最常用的类型了,即字符串类型,String是常量(final关键词修饰的),他的值不能被创建后更改,因为字符串是不可被改变的,所以可以被用来共享. Java语言为Stri ...
- Java纸牌小demo以及日历小demo
//卡牌类 public class Card { //定义卡牌的点数 public static final String[] cardName = { "3", "4 ...