2021-09-18 01:45:41
synchronized关键字是Scala中实现线程同步的核心工具,通过锁定对象monitor确保同一时刻只有一个线程访问受保护代码,从而避免共享资源的数据竞争问题。
synchronized方法:锁定方法所属对象的monitor,只有持有该对象monitor的线程才能执行该方法。
def synchronizedMethod(): Unit = this.synchronized { // 受保护的代码}synchronized代码块:允许指定任意对象作为monitor,灵活性更高。
def blockMethod(): Unit = { val lock = new Object() lock.synchronized { // 受保护的代码 }}原始代码存在三个关键问题:
object Example { private var counter: Int = 0 def increaseCounter(): Unit = this.synchronized { // 仅保护写操作 counter = counter + 1 } def printCounter(): Unit = { // 读操作未保护 println(counter) } // 在object初始化阶段启动线程(存在死锁风险) val t1 = injectFunction(increaseCounter()) val t2 = injectFunction(increaseCounter()) val t3 = injectFunction(printCounter())}printCounter未同步导致读取中间状态
线程启动时机过早可能访问未初始化对象
完整同步保护:
读写操作均通过this.synchronized保护
使用局部变量暂存同步读取结果
执行顺序控制:
通过join()方法确保主线程等待所有工作线程完成
最终结果打印反映真实并发修改结果
初始化安全:
将线程启动移至main方法
避免对象未完全初始化时启动线程
最小化同步范围:
仅保护必要代码块,减少性能损耗
避免在同步块内执行I/O操作等耗时任务
选择合适的monitor对象:
方法同步默认使用this作为monitor
代码块同步可指定专用锁对象(如private val lock = new Object())
避免死锁:
防止嵌套获取多个锁
确保锁的获取顺序一致
考虑替代方案:
对于简单原子操作,优先使用AtomicInteger等并发类
高并发场景可考虑Akka等actor模型框架
减少锁竞争:
将大锁拆分为细粒度锁
使用读写锁(如ReentrantReadWriteLock)分离读写操作
锁优化技巧:
考虑使用@volatile修饰简单变量
对于计数器场景,AtomicInteger性能通常优于同步块
基准测试:
使用JMH等工具测量同步代码性能
根据实际场景调整同步策略
通过系统理解synchronized的作用机制、作用范围及使用限制,结合完整的同步保护和合理的线程控制,可以构建出既安全又高效的Scala多线程程序。在实际开发中,应根据具体场景权衡同步粒度与性能需求,选择最适合的并发控制方案。