论坛首页 Java企业应用论坛

最简单高效的tryLock

浏览 18515 次
精华帖 (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% ,一直下不来, 直到程序结束.

这测试代码有问题, 不能这样干, 这样的测试不可靠不可信.
0 请登录后投票
   发表时间: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%,还用测试?这个测试不可靠,那也请你写一段测试程序来比较速度吧!
0 请登录后投票
   发表时间: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内存
0 请登录后投票
   发表时间:2010-09-25  
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。
0 请登录后投票
   发表时间:2010-09-25  
wkoffee 写道
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。



JDK 1.6 默认的开启了-XX:+UseBiasedLocking , 使用了偏向锁,自旋锁是1.6之前默认的,自旋锁的性能也不好。
0 请登录后投票
   发表时间: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的实现,不过它只能针对单个资源安全,不能作为多语句的原子操作。

 

 

 

是的,代码中没有让线程等待。

0 请登录后投票
   发表时间:2010-09-25  
mercyblitz 写道

 

 

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

 

正如其函数名,叫try lock,而不是lock,可以在避免当前线程直接陷入阻塞的情况下去获得锁,如果当前线程有类似很多高用户交互的行为,这种锁很重要。

 

临界区的保证是需要应用层和框架共同提供的,这不过就是一个锁。

0 请登录后投票
   发表时间:2010-09-25  
mercyblitz 写道
wkoffee 写道
我自己测下来用synchronized关键字更快,我想应该是这种spin lock有很多cas操作都是无效的,cas本身也是代价很大的。



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


并不是偏向锁的功劳,这个例子高度竞争,明显不是偏向锁擅长的类型,使用偏向锁反而会降低性能,我用了-XX:-UseBiasedLocking后速度又提高了。
0 请登录后投票
   发表时间: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呢?

0 请登录后投票
   发表时间:2010-09-25  
代码中没有让线程等待是因为这是个tryLock,我的应用中是用它来控制线程争用连接池中的连接,每个连接上都有这样一个Lock,如果tryLock成功且连接空闲状态,则修改一下状态位后立刻unlock,如果连接繁忙则直接unlock,如果tryLock不成功,则去尝试下一个连接
0 请登录后投票
论坛首页 Java企业应用版

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