论坛首页 Java企业应用论坛

最简单高效的tryLock

浏览 18571 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-09-24  
asme2u 写道
mercyblitz 写道
asme2u 写道
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倍左右

 

 

你这个有线程安全问题呢,怎么保证在tryLock 和unlock之间的线程安全(状态一直性)?

 

ReentrantLock 是利用Thread 队列,只有独占线程看到共享资源,pack其他线程,待操作完毕,下一个线程unpack继续操作。同时还有JVM底层的操作。

 

 

如果任何线程使用都遵守tryLock返回true后再去unlock,不会有线程安全问题的,compareAndSet是个原子操作

 

 

我的天啊, 在同步(互斥)中间执行的代码叫做“临界区”,AtomicX类都是Nonblocking的,怎么取保其他线程不进入“临界区”,这个不算的话。线程安全,还应该保证 Thread的读和写的数据和主存中的一致。你这个类怎么取保?

0 请登录后投票
   发表时间:2010-09-24  
asme2u 写道
hellojinjie 写道
asme2u 写道

ellojinjie 写道
性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关???

你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。

我实际应用场景是高并发,短占用,如果你应用场景从获取锁到释放锁需要很长的时间,性能不会有多少提高



看来是ReentrantLock 里的tryLock太耗时了,才会使得用AtomicBoolean实现的Lock性能比ReentryLock好

正解,只有符合锁占用的时间与获取锁的时间可比拟时,这个类才有意义,所以我列出了适用场景。


你要看情况,
建议楼主看一下为什么要引入偏向锁,就是为了解决CAS延迟问题。http://blogs.sun.com/dave/entry/biased_locking_in_hotspot

你所说的场景不过是你-client的设置罢了,多核CPU再来试试。
0 请登录后投票
   发表时间:2010-09-24  
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都不可靠了呢?这些个原子类什么时候适用?
0 请登录后投票
   发表时间:2010-09-24  
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的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。
0 请登录后投票
   发表时间:2010-09-25  
hellojinjie 写道
性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关???

你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。

jdk5后的并发包中的类基本都是基于自旋锁实现的
也有叫CAS的

以上是个人理解
0 请登录后投票
   发表时间:2010-09-25  
hellojinjie 写道
性能应该只与线程执有锁的时间和多少个线程竞争该锁有关,,为什么会和线程如何得到锁有关???

你用tryLock,应该是自旋锁这一类的吧,在我的单核的CPU上,恐怕也不会有什么性能的提高。。。

单核是没有提高,但是。。。现在单核的运行环境也不太常见。。所以,楼主这个帖子是可行的。。。

0 请登录后投票
   发表时间:2010-09-25  
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的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。

 

 

0 请登录后投票
   发表时间:2010-09-25  
我在我电脑上做了一个测试,两者差别没有楼主说的那么大,前者之比后者提高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
0 请登录后投票
   发表时间:2010-09-25  
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



同意楼上的, 以下是我分别在JDK5和JDK6下做的测试.
测试环境:
os: Windows XP Professional 2002 sp3;
cpu: Pentium(R) Dual-Core CPU E5300 @ 2.60GHz 2.60GHz;
mem: 2G;

测试结果如下:
JDK5
Lock:
300000000
57359


ReentrantLock:
300000000
56625

JDK6
Lock:
300000000
40734


ReentrantLock:
300000000
55453


LZ , 你测试的结果也贴出来看看.
0 请登录后投票
   发表时间:2010-09-25  
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%,没想明白
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics