我现在连个三目表达式都看不懂了…

2020-07-20 12:01:50 +08:00
 amiwrong123

ConcurrentLinkedQueue 的 offer 方法有个奇怪的三目表达式

*/
    public boolean offer(E e) {
        checkNotNull(e);
        final Node<E> newNode = new Node<E>(e);

        for (Node<E> t = tail, p = t;;) {
            Node<E> q = p.next;
            if (q == null) {
                // p is last node
                if (p.casNext(null, newNode)) {
                    // Successful CAS is the linearization point
                    // for e to become an element of this queue,
                    // and for newNode to become "live".
                    if (p != t) // hop two nodes at a time
                        casTail(t, newNode);  // Failure is OK.
                    return true;
                }
                // Lost CAS race to another thread; re-read next
            }
            else if (p == q)
                // We have fallen off list.  If tail is unchanged, it
                // will also be off-list, in which case we need to
                // jump to head, from which all live nodes are always
                // reachable.  Else the new tail is a better bet.
                p = (t != (t = tail)) ? t : head;
            else
                // Check for tail updates after two hops.
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }

这个三目表达式(t != (t = tail)) ? t : head;的左边看起来很奇怪,(t != (t = tail))本质上不就是(t != t)吗,那这不是肯定不成立吗?我佛了

jdk8

9484 次点击
所在节点    Java
58 条回复
TtTtTtT
2020-07-20 12:18:04 +08:00
=。=本质理解错了呀。。
x = (t != (t = tail))

newT = tail
x = t != newT
t = newT
amiwrong123
2020-07-20 12:44:06 +08:00
@TtTtTtT
你意思这个执行过程是从左到右,前一秒等号左右两边都是旧 t,后一秒等号左边是旧 t 右边是新 t

是这样的吗😂
zmj1316
2020-07-20 12:44:33 +08:00
取值有顺序的,左边的 t 早于右边的赋值吧
no1xsyzy
2020-07-20 13:00:42 +08:00
话说这也不是三目看不懂啊……
chairuosen
2020-07-20 13:11:21 +08:00
谁这么写代码我打死他,相当于 get 里干 set 的活
TtTtTtT
2020-07-20 13:47:38 +08:00
@amiwrong123 你说的我完全没弄懂。。
我给你简单解释一下:
t = tail 是用来获取当前最新的 tail 。
(t != (t = tail)) 就是检查一下 t 是不是最新的 tail,同时将 t 更新为最新的 tail 。

在 Java 中,赋值语句返回所赋的值,比如 a = 1 返回 a 。

@chairuosen JDK 里这种写法很多,这样编译的时候会减少 slots 的占用。
TtTtTtT
2020-07-20 13:48:18 +08:00
@amiwrong123 写错了,a = 1 返回 1 。
hangs
2020-07-20 13:56:29 +08:00
这里有个说明,我觉得说的很明白了

https://segmentfault.com/q/1010000022097461/a-1020000022098182

我理解一个是赋值表达式本身是有返回的,返回值正如 @TtTtTtT 所说,是被赋值的值,另一个是开头的 t,其实读的还是旧值
chairuosen
2020-07-20 14:01:38 +08:00
@TtTtTtT #6 写代码第一给人看,第二才是给机器看。如果是底层万年不变的可以用写奇技淫巧,业务代码这么写被喷成狗
amiwrong123
2020-07-20 14:34:08 +08:00
@TtTtTtT
赋值语句我懂了,而且这个比较运算之前我好像理解错了。

(t != (t = tail)) 实际上是左边的 t 先读取旧 t,然后执行到等号右边,执行右边的赋值语句,虽然赋值语句改变了 t 的值,但由于执行顺序,左边的 t 已经“感受”不到变化了。
bzj
2020-07-20 15:36:42 +08:00
@amiwrong123

道理我都懂,那为什么不直接 t !=tail 呢,就是为了后面可以写 t ?
mightofcode
2020-07-20 16:53:41 +08:00
这代码味道有点冲
SingeeKing
2020-07-20 16:59:12 +08:00
xiangyuecn
2020-07-20 17:04:43 +08:00
骚操作,并没有省代码,反而理解起来异常困难。

p = (t != (t = tail)) ? t : head;

等价于:

p= t != tail ? tail:head;
t=tail;

多写一行多好理解,为了省一行写成这样也行啊:
p= t != tail ? tail:head; t=tail; 狗头
amiwrong123
2020-07-20 17:15:19 +08:00
@bzj
我也想知道,这可能就是大佬的写法吧。。
amiwrong123
2020-07-20 17:16:27 +08:00
@SingeeKing
昨天正准备开开心心看看 ConcurrentLinkedQueue 的源码,结果就被这个三木表达式给困住了
amiwrong123
2020-07-20 17:17:23 +08:00
@xiangyuecn
墙裂同意,理解起来太困难了。

你那个写法就很清晰了。
blessingsi
2020-07-20 17:27:36 +08:00
jdk 里面这种代码太多了,上次看 concurrentmap,发现给 local 变量加了锁,翻了无数遍,才发现 local 变量后面又赋值了成员变量
amiwrong123
2020-07-20 17:43:45 +08:00
@blessingsi
哈哈,有点好奇是哪个地方。话说你是说 ConcurrentHashMap 嘛,我也刚看了 ConcurrentHashMap,还是说你看的是那个 concurrentmap 接口
yyyyfan
2020-07-20 18:10:33 +08:00
你以为的源码是大佬在写,然而其实是工人在拧螺丝

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/691522

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX