Swift中synchronized机制实现无效问题求助
嘿,作为Swift新手刚接触多线程确实得转换下思路,毕竟Swift的并发模型和Java不太一样~ 我先帮你把没写完的代码补全,再给你几种对应Java synchronized的同步实现方案,都是Swift里常用的方式:
先补全你的基础代码框架
假设你要实现的是多个线程操作同一个共享资源(比如一个计数器),先把你的代码补完整:
import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true // 被多个线程访问的共享类 class TheDemo { var counter = 0 } // 自定义线程类 public class TestThread { var name: String var theDemo: TheDemo init(_ name: String, _ theDemo: TheDemo) { self.name = name self.theDemo = theDemo } // 启动线程执行任务 func start() { Thread { [weak self] in guard let self = self else { return } // 这里是需要同步的操作 for _ in 0..<1000 { self.theDemo.counter += 1 } print("\(self.name) 执行完成,当前counter值:\(self.theDemo.counter)") }.start() } } // 测试代码 let demo = TheDemo() let thread1 = TestThread("线程1", demo) let thread2 = TestThread("线程2", demo) thread1.start() thread2.start()
不过上面的代码没有同步处理,会出现线程安全问题,counter的最终值大概率不是预期的2000,接下来给你几种可靠的同步方案:
方案1:使用NSLock(手动加锁,最接近Java synchronized)
类似Java的synchronized代码块,我们可以用NSLock给共享资源的操作加锁,保证同一时间只有一个线程能执行临界区代码:
import PlaygroundSupport import Foundation PlaygroundPage.current.needsIndefiniteExecution = true class TheDemo { var counter = 0 private let lock = NSLock() // 定义一个专属锁 // 同步方法,类似Java的synchronized方法 func increment() { lock.lock() defer { lock.unlock() } // defer保证锁一定会被释放,避免死锁 counter += 1 } } public class TestThread { var name: String var theDemo: TheDemo init(_ name: String, _ theDemo: TheDemo) { self.name = name self.theDemo = theDemo } func start() { Thread { [weak self] in guard let self = self else { return } for _ in 0..<1000 { self.theDemo.increment() // 调用同步方法 } print("\(self.name) 执行完成,当前counter值:\(self.theDemo.counter)") }.start() } } let demo = TheDemo() let thread1 = TestThread("线程1", demo) let thread2 = TestThread("线程2", demo) thread1.start() thread2.start()
这里lock.lock()和lock.unlock()就对应Java的synchronized代码块,defer语句能保证即使方法抛出异常,锁也会被释放,从根源避免死锁风险。
方案2:使用GCD串行队列(隐式同步,更贴合Swift风格)
Swift里更常用的是用GCD的串行队列实现同步:把所有需要访问共享资源的任务放到同一个串行队列里,队列会自动保证任务按顺序执行,完全不需要手动管理锁:
import PlaygroundSupport import Foundation PlaygroundPage.current.needsIndefiniteExecution = true class TheDemo { var counter = 0 private let syncQueue = DispatchQueue(label: "com.example.syncQueue") // 创建串行队列 func increment() { // 把任务放到串行队列异步执行 syncQueue.async { [weak self] in guard let self = self else { return } self.counter += 1 } // 如果需要等待任务完成后再继续,可以用sync替代async // syncQueue.sync { ... } } // 获取当前counter值也要同步,避免读取到中间的不一致值 func getCounter() -> Int { var result = 0 syncQueue.sync { result = self.counter } return result } } public class TestThread { var name: String var theDemo: TheDemo init(_ name: String, _ theDemo: TheDemo) { self.name = name self.theDemo = theDemo } func start() { Thread { [weak self] in guard let self = self else { return } for _ in 0..<1000 { self.theDemo.increment() } print("\(self.name) 执行完成,当前counter值:\(self.theDemo.getCounter())") }.start() } } let demo = TheDemo() let thread1 = TestThread("线程1", demo) let thread2 = TestThread("线程2", demo) thread1.start() thread2.start()
这种方式代码更简洁,也减少了手动锁可能带来的失误,是Swift开发者常用的同步方案。
方案3:使用Swift Actor(现代Swift并发模型,官方推荐)
从Swift 5.5开始,苹果推出了Actor模型,这是官方推荐的线程安全方案。Actor内部的所有方法默认都是线程安全的,自动避免数据竞争,完全不需要手动加锁:
import PlaygroundSupport import Foundation PlaygroundPage.current.needsIndefiniteExecution = true // 定义Actor,自动保证内部状态的线程安全 actor TheDemo { var counter = 0 func increment() { counter += 1 } func getCounter() -> Int { return counter } } public class TestThread { var name: String var theDemo: TheDemo init(_ name: String, _ theDemo: TheDemo) { self.name = name self.theDemo = theDemo } func start() { // Actor的方法需要在异步上下文中调用,用Task创建异步任务 Task { [weak self] in guard let self = self else { return } for _ in 0..<1000 { await self.theDemo.increment() } let finalCount = await self.theDemo.getCounter() print("\(self.name) 执行完成,当前counter值:\(finalCount)") } } } let demo = TheDemo() let thread1 = TestThread("线程1", demo) let thread2 = TestThread("线程2", demo) thread1.start() thread2.start()
Actor是Swift并发模型的核心,它通过await关键字处理异步调用,自动保证同一时间只有一个线程访问Actor的内部状态,是未来Swift并发的主流方式,新项目优先推荐使用。
总结一下:如果习惯Java的手动锁逻辑,用NSLock;如果想更贴合Swift的写法,用GCD串行队列;如果是Swift 5.5+的新项目,优先用Actor,它更安全也更简洁。
内容的提问来源于stack exchange,提问作者besabestin

