Scala线程安全疑问:同步方法为何无法保证计数器输出稳定?
问题解析:线程执行顺序的不确定性与同步的作用边界
你的代码核心问题不是同步块无效,而是线程启动后执行顺序完全由操作系统调度决定,你默认认为t1、t2会先执行完再轮到t3,但实际情况并非如此。
具体原因:
increaseCounter()里的this.synchronized是有效的,它确保了counter += 1是原子操作,不会出现竞态条件导致的数值错误(比如两个线程同时读取counter=0,都加1后写回,结果还是1)。- 但你启动三个线程后,
t1、t2、t3的执行顺序是不确定的:- 如果
t3先被调度执行,此时t1和t2还没修改counter,输出就是0; - 如果
t1执行完、t2还没开始时t3执行,输出就是1; - 只有当
t1和t2都执行完毕后t3才执行,输出才是2。
- 如果
- 给
printCounter()加同步也没用,因为同步只能保证读取counter时的可见性和原子性,无法改变线程的调度顺序。
解决方法:
要确保t3在t1和t2执行完成后再执行,需要在启动t3前调用t1.join()和t2.join(),让主线程等待这两个线程结束:
val t1: Thread = injectFunction(increaseCounter()) val t2: Thread = injectFunction(increaseCounter()) val t3: Thread = injectFunction(printCounter()) t1.start() t2.start() // 等待t1和t2执行完毕 t1.join() t2.join() t3.start()
这样修改后,每次输出都会是2。
补充细节:你的injectFunction参数是传名参数=> Unit,当前写法injectFunction(increaseCounter())是正确的——Scala传名参数的表达式会在被使用时才求值,也就是在线程run方法执行时才调用increaseCounter(),而非传递参数时立即执行。
内容的提问来源于stack exchange,提问作者matti1499
相关产品推荐
相关产品推荐

