锁定老帖子 主题:最简单高效的tryLock
精华帖 (0) :: 良好帖 (2) :: 新手帖 (1) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-09-25
asme2u 写道 rocketball 写道 我在我电脑上做了一个测试,两者差别没有楼主说的那么大,前者之比后者提高10%左右,我看了下JDK1.6的API源码
前者调用方法: public final boolean compareAndSet(boolean expect, boolean update) { int e = expect ? 1 : 0; int u = update ? 1 : 0; return unsafe.compareAndSwapInt(this, valueOffset, e, u); } 后者调用方法: final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } 两者的源码并没有本质区别呀,所以为什么会有lz描述的那种情况,而我测试也没有这种情况,我CPU 双核,Windows 我在公司里的开发环境(XP,双核)上测试确实是10%左右,但在CentOS X86_64 5.4 4核的服务器上跑上面的那个测试程序,大概相差2倍多,在家里的笔记本上xp, 单核的大概也是2倍多,刚才我也翻了下JDK1.6的代码,发现确实没有什么本质区别,我想原因可能在于我的测试程序(第一页里)和我的应用环境(加锁,判断,如果符合条件修改一个标志位,然后解锁)中从获取锁到释放锁的操作非常快以至于tryLock本身的操作所占的比重比较大。至于双核的XP上为什么只有10%,没想明白 顺便说一下, 你是不是以前没写个并发程序? 你有没有看CPU占用率, 这代码像是病毒, 程序一启来, CPU马上100% ,一直下不来, 直到程序结束. 这测试代码有问题, 不能这样干, 这样的测试不可靠不可信. |
|
返回顶楼 | |
发表时间:2010-09-25
chenlixun 写道 asme2u 写道 rocketball 写道 我在我电脑上做了一个测试,两者差别没有楼主说的那么大,前者之比后者提高10%左右,我看了下JDK1.6的API源码
前者调用方法: public final boolean compareAndSet(boolean expect, boolean update) { int e = expect ? 1 : 0; int u = update ? 1 : 0; return unsafe.compareAndSwapInt(this, valueOffset, e, u); } 后者调用方法: final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } 两者的源码并没有本质区别呀,所以为什么会有lz描述的那种情况,而我测试也没有这种情况,我CPU 双核,Windows 我在公司里的开发环境(XP,双核)上测试确实是10%左右,但在CentOS X86_64 5.4 4核的服务器上跑上面的那个测试程序,大概相差2倍多,在家里的笔记本上xp, 单核的大概也是2倍多,刚才我也翻了下JDK1.6的代码,发现确实没有什么本质区别,我想原因可能在于我的测试程序(第一页里)和我的应用环境(加锁,判断,如果符合条件修改一个标志位,然后解锁)中从获取锁到释放锁的操作非常快以至于tryLock本身的操作所占的比重比较大。至于双核的XP上为什么只有10%,没想明白 顺便说一下, 你是不是以前没写个并发程序? 你有没有看CPU占用率, 这代码像是病毒, 程序一启来, CPU马上100% ,一直下不来, 直到程序结束. 这测试代码有问题, 不能这样干, 这样的测试不可靠不可信. 我写的并发程序也许为你服务过,这个测试程序一看就知道会占CPU100%,还用测试?这个测试不可靠,那也请你写一段测试程序来比较速度吧! |
|
返回顶楼 | |
发表时间:2010-09-25
我在Linux上测试过了,也是10%左右。版本:
Linux version 2.6.18-164.el5 (mockbuild@builder10.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)) #1 SMP Thu Sep 3 03:28:30 EDT 2009 JDK1.6 8核16G内存 |
|
返回顶楼 | |
发表时间:2010-09-25
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。
|
|
返回顶楼 | |
发表时间:2010-09-25
wkoffee 写道 我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。
JDK 1.6 默认的开启了-XX:+UseBiasedLocking , 使用了偏向锁,自旋锁是1.6之前默认的,自旋锁的性能也不好。 |
|
返回顶楼 | |
发表时间:2010-09-25
最后修改:2010-09-25
asme2u 写道
if(l.tryLock()) { try{ // 这里能有多个线程同时到达? } finally { l.unlock } }mercyblitz 写道 asme2u 写道
mercyblitz 写道
asme2u 写道
hellojinjie 写道
asme2u 写道
ellojinjie 写道
性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关???
你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。 我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高 看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好 正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。 你要看情况, 建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。http://blogs.sun.com/dave/entry/biased_locking_in_hotspot 你所说的场景不过是你-client的设置罢了,多核CPU再来试试。 看了一下你的链接,谢谢你的提醒,确实有延迟的问题,如果这么考虑,是否CAS都不可靠了呢?这些个原子类什么时候适用? 在你的代码中,那个逻辑判断是可靠的,但是中间的执行代码是线程不安全的。 PS:CAS是可靠的,它是Wait-free的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。
是的,代码中没有让线程等待。 |
|
返回顶楼 | |
发表时间:2010-09-25
mercyblitz 写道
我的天啊, 在同步(互斥)中间执行的代码叫做“临界区”,AtomicX类都是Nonblocking的,怎么取保其他线程不进入“临界区”,这个不算的话。线程安全,还应该保证 Thread的读和写的数据和主存中的一致。你这个类怎么取保?
正如其函数名,叫try lock,而不是lock,可以在避免当前线程直接陷入阻塞的情况下去获得锁,如果当前线程有类似很多高用户交互的行为,这种锁很重要。
临界区的保证是需要应用层和框架共同提供的,这不过就是一个锁。 |
|
返回顶楼 | |
发表时间:2010-09-25
mercyblitz 写道 wkoffee 写道 我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。
JDK 1.6 默认的开启了-XX:+UseBiasedLocking , 使用了偏向锁,自旋锁是1.6之前默认的,自旋锁的性能也不好。 并不是偏向锁的功劳,这个例子高度竞争,明显不是偏向锁擅长的类型,使用偏向锁反而会降低性能,我用了-XX:-UseBiasedLocking后速度又提高了。 |
|
返回顶楼 | |
发表时间:2010-09-25
mercyblitz 写道
asme2u 写道
if(l.tryLock()) { try{ // 这里能有多个线程同时到达? } finally { l.unlock } }mercyblitz 写道 asme2u 写道
mercyblitz 写道
asme2u 写道
hellojinjie 写道
asme2u 写道
ellojinjie 写道
性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关???
你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。 我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高 看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好 正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。 你要看情况, 建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。http://blogs.sun.com/dave/entry/biased_locking_in_hotspot 你所说的场景不过是你-client的设置罢了,多核CPU再来试试。 看了一下你的链接,谢谢你的提醒,确实有延迟的问题,如果这么考虑,是否CAS都不可靠了呢?这些个原子类什么时候适用? 在你的代码中,那个逻辑判断是可靠的,但是中间的执行代码是线程不安全的。 PS:CAS是可靠的,它是Wait-free的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。
是的,代码中没有让线程等待。
CAS是个原子操作,不可能被打断,那怎么可能会有两个线程执行 lock.compareAndSet(true, false)这个都返回true呢? |
|
返回顶楼 | |
发表时间:2010-09-25
代码中没有让线程等待是因为这是个tryLock,我的应用中是用它来控制线程争用连接池中的连接,每个连接上都有这样一个Lock,如果tryLock成功且连接空闲状态,则修改一下状态位后立刻unlock,如果连接繁忙则直接unlock,如果tryLock不成功,则去尝试下一个连接
|
|
返回顶楼 | |