×

Loading...
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。

ConcurrentLinkedQueue也不是不需要锁,你可能是直接看Java,认为不需要锁。

其实,入列和出列都是要锁的。完全不锁那不乱了套了?只不过Java使用了一种叫做非阻塞的方式加锁。CAS算法利用了一些CPU的指令,可以提高并发效率。在CPU的内部其实还是要“加锁”的。比如一个8核的机器里,CPU 1 如果要做一个CAS操作,那么就必须确保这个值存在自己的高速缓存中,同时还要确保这个interconnet不存在在其他7个CPU的高速缓存中,为此它要通过System Interconnect的模块和其他7个CPU协同。在最好的情况下一般的锁消耗为60纳秒,而CAS只需要消耗40纳秒(这指所要操作的这个interconnect正好就处于自己这个CPU中,8分之1的概率?),的确可以大大提高效率。但是问题是CAS还存在一个争用重试的问题。也就是一旦线程发现所使用变量已经被其他线程所修改,那么它就必须重新做CAS,重新尝试写入队列。在这种情况下,如果程序是一种高并发状态的话,CAS的效率也会比正常的锁效率更低。

上面写了那么多,其实也是废话。只是想说一点,原子操作不等于无开销的操作。只是加锁方式的不同。希望未来还会有更多的方式吧。
Report

Replies, comments and Discussions:

  • 工作学习 / 学科技术 / 问个问题
    为什么说,使用了event系统后,相对于线程锁效率大大提高?
    难道往event对列里面添加消息是不需要锁的?两个线程同时发出消息写入的时候如何处理?

    同理,更新immutable object 状态的时候为什么不需要锁?
    • 1. 效率提高,在于线程之间除了标准的event操作不再锁定critical section。2.event操作,包括添加消息,会加锁。3. immutable object不更新状态,所以不用加锁。
      • immutable obj自己是不会变的。但是实际使用的时候是采用一种乐观锁的状态。(如果完全不变,那就失去意义了)
        • 不对。immutable不用乐观锁。如果你觉得不变就失去意义,应该是用的不对。把你的例子拿出来,大家看看。
          • 比如我有一个共享变量,多读少写的那种
            很多线程读,少数线程写。这个时候把这个变量设成immutable,那么当这个对象改变的时候,其实是用一个新的immutable替代了旧的immutable。那么读的线程比较版本号来确定自己读到的是不是最新的。

            如果这个例子还不清楚的话,那就再多问一句。如果一个immutable的对象真的是不变的,那为啥还要共享呢?一个完全固定不变的东西,难道不应该直接就给线程一个值就结束了?

            当然,如果你说象string那样,通过immutable来节省内存。这是对的。但是它的另一个重大好处就是共享变量。我谈的是这一部分。
            • 共享变量是shared variable吧?和immutable正相反,immutable对应的是值不是变量。如果用event-based,线程之间的数据交流是通过event,而不是用共享的变量。
              很多线程读,少数线程写。

              要改成很多线程读,一个线程写。

              这个时候把这个变量设成immutable,那么当这个对象改变的时候,其实是用一个新的immutable替代了旧的immutable。

              这个可以有。

              那么读的线程比较版本号来确定自己读到的是不是最新的。

              通常没必要,要看你的需求,根据需求也有别的做法。

              如果一个immutable的对象真的是不变的,那为啥还要共享呢?

              一个就像你说的,通过immutable来节省内存。更重要的是线程之间的数据交流。而用不变的值来交换数据比用变量安全得多。

              一个完全固定不变的东西,难道不应该直接就给线程一个值就结束了?

              可以这么说。这样你是不是觉得很简单。把复杂的事情简单化,就是使用值代替变量的初衷。

    • 我抬头看到书房的两扇窗户,有一扇能打开,带锁扣。另一扇是固定的,没锁扣。固定的窗户要锁扣做什么?
    • 这位同学,先学习一下erlang,把基础知识补充一下,另外队列加消息本来就不需要锁,看ConcurrentLinkedQueue
      另外, immutable不节省内存,是用空间换时间的做法,还有就是搞清楚,immutable instance, variable 和 data structure 之间的关系。对象不变,reference 变啊。
      • 你说的这些呢,我都懂的。但是immutable的确可以省空间,比如java的string,你要是不懂的话我可以和你细说。
      • ConcurrentLinkedQueue也不是不需要锁,你可能是直接看Java,认为不需要锁。
        其实,入列和出列都是要锁的。完全不锁那不乱了套了?只不过Java使用了一种叫做非阻塞的方式加锁。CAS算法利用了一些CPU的指令,可以提高并发效率。在CPU的内部其实还是要“加锁”的。比如一个8核的机器里,CPU 1 如果要做一个CAS操作,那么就必须确保这个值存在自己的高速缓存中,同时还要确保这个interconnet不存在在其他7个CPU的高速缓存中,为此它要通过System Interconnect的模块和其他7个CPU协同。在最好的情况下一般的锁消耗为60纳秒,而CAS只需要消耗40纳秒(这指所要操作的这个interconnect正好就处于自己这个CPU中,8分之1的概率?),的确可以大大提高效率。但是问题是CAS还存在一个争用重试的问题。也就是一旦线程发现所使用变量已经被其他线程所修改,那么它就必须重新做CAS,重新尝试写入队列。在这种情况下,如果程序是一种高并发状态的话,CAS的效率也会比正常的锁效率更低。

        上面写了那么多,其实也是废话。只是想说一点,原子操作不等于无开销的操作。只是加锁方式的不同。希望未来还会有更多的方式吧。
        • 未来更多的方式是什么?
          呵呵,比如讲,量子纠缠?期待啊。
        • 节省空间的栗子都你都举错了,比较有效节省空间的是 树 的immutable 结构,string刚好是反例,特别过了1.7以前。所以...
          • String为什么是反例?请讲讲看?
          • immutable String 也有省空间的时候, 如果在pool里面旧的object 还没有被回收,合适的话,它还可被其它新的variable重新引用, 不过好象没有什么人去关心immutable String省或费空间的事情,immutable String主要在与有助数据结构的稳定,比如hashcode比较固定。
            • java 7u6 之后 string的实现有很多更改,以前一些“j节省空间”的做法去掉了,这个大家可以google一下,主要是性能方面的考虑
              • Oracle java 7u6对String class的大改动是为了解决memory leak的bug。其他vendor的Java还有采用老结构的。
        • 原子性操作不是blocking,天啊,CS老师们要哭死啊,CAS的CPU消耗不是因为blocking啊,你自己的之前的语意锁是blocking,突然来到这画风一变就变原子性操作了,CAS饰标准的non-blocking啊。
          • 兄弟你技术不错,就是脾气差点。限制发展啊。呵呵。
            我一开始的感觉,就是觉得这东西就是个spinLock,所以就说锁了。block就是阻塞,这没什么好争的。
            • 成,俺这逗机灵的语气都成脾气不好了,难怪还是低价码农一枚,给跪……
        • 另外,把SQL上的ACID 操作术语放到内存上,这个都已经够奇葩了...按这个思路我们来聊聊啥是STM
      • 对象不变,reference 变啊,这正是我前面所讨论的乐观锁的point。
        当然是变reference,对象都已经告诉你是immutable的了,你还变什么变?只是前面的争论在于immutable对象有没有可能在这种方式下使用而已。我认为会有,geekcode认为不会有。这个就不用争辩了,用法不同,不用也无所谓。
        举一个例子,比如讲Java自己对于incrementAndGet方法的实现

        public final int incrementAndGet() {
        for (;;) { // 这里就是乐观锁的表现。它假设自己应该是能够成功的,所以不怕这个for
        int current = get(); //这里,你可以把current就定义成final,那就是immutable对象。
        int next = current + 1; //这里,如果把next定义为final,那就是一个新建的immutable对象
        if (compareAndSet(current, next)) //此处加锁,改reference
        return current;
        }
        }

        public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update); //原子操作,你改reference是一定要加这个锁的。不加锁是绝对不可能实现的。
        }
        • 上面写错了一个
          应该是current和next就是两个reference,但是这两个reference指向的对象是immutable
        • 你们真的是内行吗?我从业这么多年从来没有听说过“乐观锁”这词。
          • 那么您的知识水平严重有偏差,这个基本上所有相关SQL原子性的时候都会提到,HIBERNATE里面还是关键字,请之前GOOGLE一下,虽然这个名称的确有错,学术上应该成为OCC
            或者叫乐观并发处理,叫乐观锁是sql 那边养成的习惯
            • 您能不能不要张口闭口你水平太差之类?
              人都是从不懂到懂的。我体会有些人是学得多所以知道得多。而有些人是能自己提出问题再寻找问题的答案。能到这个坛子里问问题的都是好同志。
              • 请观察以前几贴,好像只有大哥您用上了 你不懂 这个词,俺一般只说各位的知识面缺乏,请更新。各位懂不懂我猜不准,但知识体系有偏差是可以比较的
                • 不做点对比你就浑身不自在?
                  • 不是大哥您自己以前说的吗?“还处在不知道自己不懂的阶段,希望大家都来提问题”,这哪是对比呢?
                    • 嗯,所以你针对我,我也没话说。可是这位arrowroot大哥又怎么惹上你了?
                      开始我也以为你就是对我,算了。后来发现你这个人一贯如此啊。
                      • 好吧,逗机灵和您觉得针对这是代沟问题,没对arrowroot有啥意见。俺和木子聊得不是好好地嘛,咱这一贯还算顺溜。
          • arrowroot 大哥,既然我是针对您了,跪求解释啥叫內行不内行。可能我是外行人,不知道哪儿搞错了,所以针对您了。
            • 我也有可能是小妹呀,或者大妈,或者大叔。我工作中从未听说,面试中从未听说,读资料时从未碰到你说的“乐观锁”这词。
      • ConcurrentLinkedQueue好象是thread safty, 那就有synchronized在里头lock住了一些共享代码,只是不lock整个collection,而是部分而已。
        • 这个真不是,thread safe并不一定是必然有synchronized keyword在实现里面的,而CLQ正好是标准教程,CAS和transient volatile才是重点
          • +1, 越新的version,越会用到CAS和transient volatile
            • 话是这么说,jvm这个坑还是有的,要是metal没有相关cas的指令,还是会 fall back到软cas实现的。 +1
              • 到了那个版本才能全面实现那些重点呢,现在大多java guy和他们的code 好象还在JVM里面。
                • 嗯,我们带着发展的眼光看吧……好多时候java都在追赶,跨平台不能没有trade off不是?