V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  amiwrong123  ›  全部回复第 34 页 / 共 46 页
回复总数  909
1 ... 30  31  32  33  34  35  36  37  38  39 ... 46  
@guyeu
是,我那个地方看错了,还是基础不扎实。

没想到还有论文,惊到了,回头看看
2020-05-23 10:45:41 +08:00
回复了 amiwrong123 创建的主题 Java AQS 里的 setHeadAndPropagate 以及关于 PROPAGATE 信号的疑问?
@guyeu
@luckyrayyy
谢谢回复,之前这块确实想错了,看来以后发帖前还是得看仔细,我承认错误。

不过看完还是有疑问。分析如下


- 入参`node`所代表的线程(这个 node 的 Thread 成员)一定是当前执行的线程,
- 看第一个 if 的判断:
- 如果`propagate > 0`成立的话,说明还有剩余共享锁可以获取,那么短路后面条件。
- 如果`propagate = 0`成立的话,说明没有剩余共享锁可以获取了,按理说不需要唤醒后继的。也就是说,很多情况下,调用 doReleaseShared,会造成 acquire thread 不必要的唤醒。
- 继续看,如果`propagate > 0`不成立,而`h.waitStatus < 0`成立。这说明旧 head 的 status<0 。但如果你看 doReleaseShared 的逻辑,会发现在 unparkSuccessor 之前就会 CAS 设置 head 的 status 为 0 的,在 unparkSuccessor 也会进行一次 CAS 尝试,因为 head 的 status 为 0 代表一种中间状态( head 的后继代表的线程已经唤醒,但它还没有做完工作),或者代表 head 是 tail 。而这里旧 head 的 status<0,只能是由于 doReleaseShared 里的`compareAndSetWaitStatus(h, 0, Node.PROPAGATE)`的操作,而且由于当前执行 setHeadAndPropagate 的线程只会在最后一句才执行 doReleaseShared,所以出现这种情况,一定是因为有另一个线程在调用 doReleaseShared 才能造成,而这很可能是因为在中间状态时,又有人释放了共享锁。
- 继续看,如果`propagate > 0`不成立,且`h.waitStatus < 0`不成立,而第二个`h.waitStatus < 0`成立。注意,第二个`h.waitStatus < 0`里的 h 是新 head (很可能就是入参 node )。第一个`h.waitStatus < 0`不成立很正常,因为它一般为 0 。第二个`h.waitStatus < 0`成立也很正常,因为只要新 head 不是队尾,那么新 head 的 status 肯定是 SIGNAL 。所以这种情况只会造成不必要的唤醒。


简单的说,我认为,检查第一个`h.waitStatus < 0`,是因为被唤醒的线程处于中间状态,而 doReleaseShared 在这个中间状态,只会设置`compareAndSetWaitStatus(h, 0, Node.PROPAGATE)`,不会调用 unparkSuccessor(h);,因为线程已经被唤醒了。

但检查第二个`h.waitStatus < 0`就有点想不通,感觉他只会造成不必要的唤醒?好奇怪
@wutiantong
我承认我菜,那层主能讲解下这个常识吗
@luckyrayyy
哈哈哈,可以,直接问本人
@vitoliu
卧槽,无情~
2020-05-21 18:36:06 +08:00
回复了 amiwrong123 创建的主题 Java AQS 里的 setHeadAndPropagate 以及关于 PROPAGATE 信号的疑问?
我好后悔,我是不是应该弄个吸引人的标题的…
@hfc
是嘛,在 interrupt 的源码里能看到有调用 unpark 的吗
2020-05-17 20:18:30 +08:00
回复了 amiwrong123 创建的主题 Java AQS 里 hasQueuedPredecessors 里为啥要先读取 tail 成员啊?
@liangdu
>只是你对“语序逻辑是否依赖”没理解对而已,其实是有依赖的

我怎么看怎么赶脚 Node t = tail; Node h = head;这两句没啥依赖关系啊。

对了,我又突然想起来了,难道是这是两次 volatile 写操作,然后会在每次 volatile 写后面,加 StoreStore 和 StoreLoad 屏障,然后才能 这两句 不会被 指令重排序 ?是因为这个原因吗
2020-05-17 15:25:28 +08:00
回复了 amiwrong123 创建的主题 Java AQS 里 hasQueuedPredecessors 里为啥要先读取 tail 成员啊?
@xingda920813
这篇我看了,大概就是我图片里那个意思。 但需要考虑什么 happen-before 语义不呢
@adguy
@freebird1994
@gexyuzz
好吧,我发现我看错源码了,问了个 sb 的问题。此帖沉了。
@iffi
那如果修改 AtomicIntegerArray 为 private volatile int[] array,再修改 set 函数为 public final void set(int i, int newValue) {array[i] = newValue; } 。

这样是否可以保证 可见性 呢
@hoholiday
了解了啊。要知道大部分原子类,其数据成员都是 volatile 的,其 get 方法都是直接 return 成员,而不是通过 unsafe 对象 get 。
但原子数组类,在设计上就不一样了。
2020-05-10 17:50:02 +08:00
回复了 amiwrong123 创建的主题 Java AtomicStampedReference 的 CAS 操作,这么理解对吗
@orangex
理论上版本号应该越来越大,但这里提供的函数,就是随便设置版本号。

我也感觉后者不成立。因为 current 只是一个局部变量,就算线程切出去又切回来,此时 current 就变成了一个孤儿了(只有 current 局部引用指向它),假设其他线程 趁你切出去更新了 pair 对象。此时,pair 成员一定是新的 pair 对象。此时,再通过 casPair 判断,发现 current 局部变量就不是旧引用了。
@sioncheng
看了方法签名也是一脸懵啊,我都 System.in.close()了,那 System.in 这个 InputStream 此时感觉应该处于 the end of the stream is detected 的状态啊
@pursuer
这么说,有可能是哈。我还忘说自己的环境了,win10,jdk8.也许作者跑程序不是在 Windows 上跑的。
@SoloCompany
所以我那个线程,已经产生了 IllegalMonitorStateException,但我没 catch 住呗,所以没有打印。由于有异常没 catch 住,自然我那个线程也处于死亡状态了呗
@etoah
谢谢,大概明白了。比如,我可以 Entrance 里改成 synchronized(Entrance.getClass()) {//run 里面的所有逻辑},这样就可以了。

虽说这样改变程序的本意,Entrance 代表各个大门,那自然各个大门可以同时进入人,但这样改了,即使有五个大门,同一时刻,只能有一个大门可以进人。
@etoah
谢谢回答,你这么一理,确实是对上了。
把那个语句拆分成两句确实清楚了,还有就是拆分后的第二句的执行顺序,跟第一句的不一样的原因:是不是因为,线程之间没有互斥锁,所以执行顺序就是随机的(跟线程池有关吗)?

当然,每次打印结果都可能不一样,但至少,能用你的方法对上。
@hfc
哎,所以现在我就有点没看懂这个打印结果了。。
@hfc
不是吧,我感觉只有一个 Count 对象存在吧。作为一个静态域
1 ... 30  31  32  33  34  35  36  37  38  39 ... 46  
关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2679 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 24ms · UTC 03:11 · PVG 11:11 · LAX 20:11 · JFK 23:11
Developed with CodeLauncher
♥ Do have faith in what you're doing.