`
asme2u
  • 浏览: 4371 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

最简单高效的tryLock

阅读更多
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author asme2u
 */
public class Lock {

    private AtomicBoolean lock = new AtomicBoolean(true);

    public boolean tryLock() {
        return lock.compareAndSet(true, false);
    }

    public void unlock() {
        lock.set(true);
    }

}

 

原理:CAS

 

优点:

     速度快,约是ReentrantLock的2-3倍

 

 缺点:

     需JDK5.0+

     无条件对象且不可重入

     未获取锁时直接调用unlock不抛IllegalMonitorStateException所以代码必须严格保证获取锁后才能调用unlock

 

适用场景:

    不需要条件对象且当ReentrantLock的tryLock影响了你的性能的时候

 

我的应用场景:

    最近项目中通信程序中的客户端的socket长连接的连接池,客户端使用连接具有高并发但占用连接时间非常短的特点,使用这个类代替ReentrantLock,性能提高了3倍左右

分享到:
评论
43 楼 daly1987 2011-12-14  
确实不错,项目上也在用,用AtomicInteger也可以的
42 楼 beneo 2010-09-25  
asme2u 写道
mercyblitz 写道
asme2u 写道
有判断语句,不光只有一条修改语句
大致是这样的意思:
if(l.tryLock()) {
  if(!busyFlag) {
    busyFlag = true;
  }

  l.unlock();
}

那个标志是个volatile

  看来你领悟的奥义了。

呵呵,谈不上领悟,到是确实没注意到也没用到b1=!b2这样的情况,所以没明白为什么你说volatile也还存在问题


volatile 只能保证可见,不能保证原子

你在try finally块保证了原子

我猜他是这个意思
41 楼 asme2u 2010-09-25  
mercyblitz 写道
asme2u 写道
有判断语句,不光只有一条修改语句
大致是这样的意思:
if(l.tryLock()) {
  if(!busyFlag) {
    busyFlag = true;
  }

  l.unlock();
}

那个标志是个volatile

  看来你领悟的奥义了。

呵呵,谈不上领悟,到是确实没注意到也没用到b1=!b2这样的情况,所以没明白为什么你说volatile也还存在问题
40 楼 mercyblitz 2010-09-25  
asme2u 写道
有判断语句,不光只有一条修改语句
大致是这样的意思:
if(l.tryLock()) {
  if(!busyFlag) {
    busyFlag = true;
  }

  l.unlock();
}

那个标志是个volatile

  看来你领悟的奥义了。
39 楼 asme2u 2010-09-25  
有判断语句,不光只有一条修改语句
大致是这样的意思:
if(l.tryLock()) {
  if(!busyFlag) {
    busyFlag = true;
  }

  l.unlock();
}

那个标志是个volatile
38 楼 mercyblitz 2010-09-25  
asme2u 写道
mercyblitz 写道
asme2u 写道
mercyblitz 写道
asme2u 写道
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况


恩,volatile 还是不行,还是因为原子操作的问题。

volatile不支持并发修改,但是能保证修改被立刻看到,又为何不行?
不过以前在那里看到说JDK5.0前volatile实现得不好,没太关注,早不用老版本了



volatile 支持并发修改,并且保证了JSL规范中定义的Happens-before关系。

但是由于它是偏续关系,所以不满足“因果一致性

比如:

volatile boolean b1;
volatile boolean b2;

如果b2依赖于b1,比如
{
   //b1可能是true或者false;
   b2 = !b1; //如果是volatile的关系,b2不确定。但是如果b1,b2在同步中,那么b1和b2的值都被锁定了。
    
}


谢谢,你这么一说我明白了,如果只是对一个volatile操作就如我所说的,仅仅一个标志而已,就没问题了吧


对的,如果只有一个变量的话,也没有必要任何辅助代。



37 楼 asme2u 2010-09-25  
mercyblitz 写道
asme2u 写道
mercyblitz 写道
asme2u 写道
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况


恩,volatile 还是不行,还是因为原子操作的问题。

volatile不支持并发修改,但是能保证修改被立刻看到,又为何不行?
不过以前在那里看到说JDK5.0前volatile实现得不好,没太关注,早不用老版本了



volatile 支持并发修改,并且保证了JSL规范中定义的Happens-before关系。

但是由于它是偏续关系,所以不满足“因果一致性

比如:

volatile boolean b1;
volatile boolean b2;

如果b2依赖于b1,比如
{
   //b1可能是true或者false;
   b2 = !b1; //如果是volatile的关系,b2不确定。但是如果b1,b2在同步中,那么b1和b2的值都被锁定了。
    
}


谢谢,你这么一说我明白了,如果只是对一个volatile操作就如我所说的,仅仅一个标志而已,就没问题了吧
36 楼 mercyblitz 2010-09-25  
asme2u 写道
mercyblitz 写道
asme2u 写道
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况


恩,volatile 还是不行,还是因为原子操作的问题。

volatile不支持并发修改,但是能保证修改被立刻看到,又为何不行?
不过以前在那里看到说JDK5.0前volatile实现得不好,没太关注,早不用老版本了



volatile 支持并发修改,并且保证了JSL规范中定义的Happens-before关系。

但是由于它是偏续关系,所以不满足“因果一致性

比如:

volatile boolean b1;
volatile boolean b2;

如果b2依赖于b1,比如
{
   //b1可能是true或者false;
   b2 = !b1; //如果是volatile的关系,b2不确定。但是如果b1,b2在同步中,那么b1和b2的值都被锁定了。
    
}

35 楼 asme2u 2010-09-25  
mxswl 写道
软件包 java.util.concurrent.atomic 的描述:

类的小工具包,支持在单个变量上解除锁定的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。

楼主的这个锁和自旋锁还是有区别的,因为用户有机会定制"就算拿不到锁,我要做的事情"

public void lock() {
for (;;) {
if (lock.compareAndSet(true, false)) {
break;
}
try {
Thread.sleep(0, 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


模拟自旋锁,可否?
34 楼 mxswl 2010-09-25  
软件包 java.util.concurrent.atomic 的描述:

类的小工具包,支持在单个变量上解除锁定的线程安全编程。事实上,此包中的类可将 volatile 值、字段和数组元素的概念扩展到那些也提供原子条件更新操作的类。

楼主的这个锁和自旋锁还是有区别的,因为用户有机会定制"就算拿不到锁,我要做的事情"
33 楼 asme2u 2010-09-25  
mercyblitz 写道
asme2u 写道
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况


恩,volatile 还是不行,还是因为原子操作的问题。

volatile不支持并发修改,但是能保证修改被立刻看到,又为何不行?
不过以前在那里看到说JDK5.0前volatile实现得不好,没太关注,早不用老版本了
32 楼 mercyblitz 2010-09-25  
asme2u 写道
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况


恩,volatile 还是不行,还是因为原子操作的问题。
31 楼 asme2u 2010-09-25  
的确,中间的那段,我们开发的时候意识到了,使用的是一个volatile变量作为标志繁忙状态而已,可能在别的场合下,中间的那段会发生CPU缓存中的变量与内存中的不一致的情况
30 楼 mercyblitz 2010-09-25  
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">
<pre name="code" class="java">if(l.tryLock()) {
  try{

   // 这里能有多个线程同时到达?

  } finally {
    l.unlock
  }

}</pre>
 mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">hellojinjie 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<br><div class="quote_title">ellojinjie 写道</div>
<div class="quote_div">性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关??? <br><br>你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。</div>
<br>我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高 <br><br><br>
</div>
<br>看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好</div>
<br>正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。 <br>
</div>
<br><br>你要看情况, <br>建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。<a href="http://blogs.sun.com/dave/entry/biased_locking_in_hotspot" target="_blank">http://blogs.sun.com/dave/entry/biased_locking_in_hotspot</a> <br><br>你所说的场景不过是你-client的设置罢了,多核CPU再来试试。</div>
<br>看了一下你的链接,谢谢你的提醒,确实有延迟的问题,如果这么考虑,是否CAS都不可靠了呢?这些个原子类什么时候适用?</div>
<br><br><br>在你的代码中,那个逻辑判断是可靠的,但是中间的执行代码是线程不安全的。 <br><br>PS:CAS是可靠的,它是Wait-free的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。</div>
<p> </p>
<p> </p>
</div>
<p> </p>
<p>是的,代码中没有让线程等待。</p>
<p> </p>
</div>
<p>CAS是个原子操作,不可能被打断,那怎么可能会有两个线程执行 lock.compareAndSet(true, false)这个都返回true呢?</p>
</div>
<p> </p>
<p>恩,你是对的,不过中间代码端的资源没有同步主存。</p>
29 楼 asme2u 2010-09-25  
代码中没有让线程等待是因为这是个tryLock,我的应用中是用它来控制线程争用连接池中的连接,每个连接上都有这样一个Lock,如果tryLock成功且连接空闲状态,则修改一下状态位后立刻unlock,如果连接繁忙则直接unlock,如果tryLock不成功,则去尝试下一个连接
28 楼 asme2u 2010-09-25  
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">
<pre name="code" class="java">if(l.tryLock()) {
  try{

   // 这里能有多个线程同时到达?

  } finally {
    l.unlock
  }

}</pre>
 mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">hellojinjie 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<br><div class="quote_title">ellojinjie 写道</div>
<div class="quote_div">性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关??? <br><br>你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。</div>
<br>我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高 <br><br><br>
</div>
<br>看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好</div>
<br>正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。 <br>
</div>
<br><br>你要看情况, <br>建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。<a href="http://blogs.sun.com/dave/entry/biased_locking_in_hotspot" target="_blank">http://blogs.sun.com/dave/entry/biased_locking_in_hotspot</a> <br><br>你所说的场景不过是你-client的设置罢了,多核CPU再来试试。</div>
<br>看了一下你的链接,谢谢你的提醒,确实有延迟的问题,如果这么考虑,是否CAS都不可靠了呢?这些个原子类什么时候适用?</div>
<br><br><br>在你的代码中,那个逻辑判断是可靠的,但是中间的执行代码是线程不安全的。 <br><br>PS:CAS是可靠的,它是Wait-free的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。</div>
<p> </p>
<p> </p>
</div>
<p> </p>
<p>是的,代码中没有让线程等待。</p>
<p> </p>
</div>
<p>CAS是个原子操作,不可能被打断,那怎么可能会有两个线程执行 lock.compareAndSet(true, false)这个都返回true呢?</p>
27 楼 wkoffee 2010-09-25  
mercyblitz 写道
wkoffee 写道
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。



JDK 1.6 默认的开启了-XX:+UseBiasedLocking , 使用了偏向锁,自旋锁是1.6之前默认的,自旋锁的性能也不好。


并不是偏向锁的功劳,这个例子高度竞争,明显不是偏向锁擅长的类型,使用偏向锁反而会降低性能,我用了-XX:-UseBiasedLocking后速度又提高了。
26 楼 mxswl 2010-09-25  
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<p> </p>
<p> </p>
<p>我的天啊, 在同步(互斥)中间执行的代码叫做“临界区”,AtomicX类都是Nonblocking的,怎么取保其他线程不进入“临界区”,这个不算的话。线程安全,还应该保证 Thread的读和写的数据和主存中的一致。你这个类怎么取保?</p>
</div>
<p> </p>
<p>正如其函数名,叫try lock,而不是lock,可以在避免当前线程直接陷入阻塞的情况下去获得锁,如果当前线程有类似很多高用户交互的行为,这种锁很重要。</p>
<p> </p>
<p>临界区的保证是需要应用层和框架共同提供的,这不过就是一个锁。</p>
25 楼 mercyblitz 2010-09-25  
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">
<pre name="code" class="java">if(l.tryLock()) {
  try{

   // 这里能有多个线程同时到达?

  } finally {
    l.unlock
  }

}</pre>
 mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">mercyblitz 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<div class="quote_title">hellojinjie 写道</div>
<div class="quote_div">
<div class="quote_title">asme2u 写道</div>
<div class="quote_div">
<br><div class="quote_title">ellojinjie 写道</div>
<div class="quote_div">性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关??? <br><br>你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。</div>
<br>我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高 <br><br><br>
</div>
<br>看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好</div>
<br>正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。 <br>
</div>
<br><br>你要看情况, <br>建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。<a href="http://blogs.sun.com/dave/entry/biased_locking_in_hotspot" target="_blank">http://blogs.sun.com/dave/entry/biased_locking_in_hotspot</a> <br><br>你所说的场景不过是你-client的设置罢了,多核CPU再来试试。</div>
<br>看了一下你的链接,谢谢你的提醒,确实有延迟的问题,如果这么考虑,是否CAS都不可靠了呢?这些个原子类什么时候适用?</div>
<br><br><br>在你的代码中,那个逻辑判断是可靠的,但是中间的执行代码是线程不安全的。 <br><br>PS:CAS是可靠的,它是Wait-free的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。</div>
<p> </p>
<p> </p>
</div>
<p> </p>
<p>是的,代码中没有让线程等待。</p>
24 楼 mercyblitz 2010-09-25  
wkoffee 写道
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。



JDK 1.6 默认的开启了-XX:+UseBiasedLocking , 使用了偏向锁,自旋锁是1.6之前默认的,自旋锁的性能也不好。

相关推荐

    汪文君高并发编程实战视频资源全集

     高并发编程第三阶段04讲 利用CAS构造一个TryLock自定义显式锁-增强并发情况下.mp4  高并发编程第三阶段05讲 AtomicBoolean源码分析.mp4  高并发编程第三阶段06讲 AtomicLong源码分析.mp4  高并发编程第三阶段07...

    汪文君高并发编程实战视频资源下载.txt

     高并发编程第三阶段04讲 利用CAS构造一个TryLock自定义显式锁-增强并发情况下.mp4  高并发编程第三阶段05讲 AtomicBoolean源码分析.mp4  高并发编程第三阶段06讲 AtomicLong源码分析.mp4  高并发编程第三阶段07...

    sesvc.exe 阿萨德

    get 方法看起来就要简单许多了。 首先将 key hash 之后取得所定位的桶。 如果桶为空则直接返回 null 。 否则判断桶的第一个位置(有可能是链表、红黑树)的 key 是否为查询的 key,是就直接返回 value。 如果第一个不...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    配16小时多媒体教学视频,高效、直观 一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让知识环环相扣,降低了学习的难度 通过大量的比喻、类比、对比和图示等多种讲解方式,学习效果好 对Java语言的...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    配16小时多媒体教学视频,高效、直观 一一击破Java入门可能会遇到的难点和疑惑 抽丝剥茧,层层推进,让知识环环相扣,降低了学习的难度 通过大量的比喻、类比、对比和图示等多种讲解方式,学习效果好 对Java语言的...

    CLR.via.C#.(中文第3版)(自制详细书签)Part1

    · 理解基元类型、值类型和引用类型的行为,从而最高效地定义和使用它们 · 使用泛型和接口来定义可重用的算法 · 高效使用特定的CLR类型——委托、枚举、定制attribute、数组和字符串 · 理解垃圾回收器是如何管理...

    CLR.via.C#.(中文第3版)(自制详细书签)

    · 理解基元类型、值类型和引用类型的行为,从而最高效地定义和使用它们 · 使用泛型和接口来定义可重用的算法 · 高效使用特定的CLR类型——委托、枚举、定制attribute、数组和字符串 · 理解垃圾回收器是如何...

    CLR.via.C#.(中文第3版)(自制详细书签)Part3

    · 理解基元类型、值类型和引用类型的行为,从而最高效地定义和使用它们 · 使用泛型和接口来定义可重用的算法 · 高效使用特定的CLR类型——委托、枚举、定制attribute、数组和字符串 · 理解垃圾回收器是如何管理...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    · 理解基元类型、值类型和引用类型的行为,从而最高效地定义和使用它们 · 使用泛型和接口来定义可重用的算法 · 高效使用特定的CLR类型——委托、枚举、定制attribute、数组和字符串 · 理解垃圾回收器是如何管理...

Global site tag (gtag.js) - Google Analytics