定義:
同步:
等帶任務(wù)執(zhí)行完畢再return跷跪,在多線程的領(lǐng)域,當(dāng)兩個(gè)或兩個(gè)以上的線程共享某些資源或需要相互配合來完成某些工作時(shí)齐板,就必須通過線程同步來協(xié)調(diào)各個(gè)線程運(yùn)行的次序吵瞻。
比如在線程A和B配合工作時(shí),A執(zhí)行到一定程度時(shí)要依靠B的某個(gè)結(jié)果甘磨,于是停下來橡羞,示意B運(yùn)行;B依言執(zhí)行济舆,再將結(jié)果給A卿泽;A再繼續(xù)操作∽叹酰或者當(dāng)線程A和B共享一個(gè)資源時(shí)又厉,如果同一時(shí)間讀寫這個(gè)資源,就會(huì)發(fā)生資源競(jìng)爭(zhēng)的問題椎瘟,這時(shí)就只能允許某個(gè)時(shí)間點(diǎn)只有一個(gè)線程占有資源覆致,另外一個(gè)線程等待,這也是線程同步肺蔚。
異步:
不用等待任務(wù)執(zhí)行完畢就return煌妈,如果一個(gè)資源被其他線程訪問,在等待訪問的同時(shí)可以先去執(zhí)行其他任務(wù)
同步任務(wù):sync
不會(huì)開啟新的線程宣羊,在當(dāng)前線程中執(zhí)行任務(wù)璧诵,執(zhí)行完一個(gè)再執(zhí)行下一個(gè),需要等待
異步任務(wù):async
是彼此獨(dú)立的仇冯,可以不需要等待某一件事完成后再工作之宿,和并行隊(duì)列配合使用無(wú)法確定任務(wù)的執(zhí)行順序。執(zhí)行異步任務(wù)可能會(huì)創(chuàng)建新的線程苛坚。
串行隊(duì)列:
隊(duì)列中的任務(wù)一個(gè)一個(gè)的執(zhí)行比被,前一個(gè)任務(wù)不執(zhí)行完畢,隊(duì)列不會(huì)調(diào)度
并行隊(duì)列:
只要有空閑的線程泼舱,隊(duì)列就會(huì)調(diào)度當(dāng)前任務(wù)等缀,交給線程去執(zhí)行,不用等待上一個(gè)任務(wù)執(zhí)行完畢娇昙。
1尺迂、常見問題
死鎖場(chǎng)景 Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
let queue = DispatchQueue(label: "queue",qos: .default, attributes: [])
queue.async { //開辟子線程
self.queue.sync { // 不開辟新線程,在當(dāng)前子線程執(zhí)行block,發(fā)生死鎖噪裕,外部的block等內(nèi)部的block執(zhí)行完畢才算結(jié)束蹲盘,內(nèi)部的block等外部的block執(zhí)行完再執(zhí)行自己
}
}
queue.sync {
self.queue.sync {
}
}
// 在主線程中向主隊(duì)列中同步添加方法,發(fā)生死鎖膳音,在子線程中添加沒有問題
DispatchQueue.main.sync {
}
2辜限、柵欄,在全局隊(duì)列中無(wú)效
func dispatchBarrier() {
concurrentQueue.async {
self.printCurrentThread(sort: "1111")
}
concurrentQueue.async(flags: DispatchWorkItemFlags.barrier) {
self.printCurrentThread(sort: "22222")
}
concurrentQueue.async {
self.printCurrentThread(sort: "333333")
}
printCurrentThread(sort: "end")
}
面試題
1严蓖、死鎖
print("----111---\(Thread.current)")
queue.async { [weak self] in
print("----222---\(Thread.current)")
self?.queue.sync {
print("----3333---\(Thread.current)")
}
print("----44444---\(Thread.current)")
}
print("---555---\(Thread.current)")
----111---<_NSMainThread: 0x6000023d00c0>{number = 1, name = main}
---555---<_NSMainThread: 0x6000023d00c0>{number = 1, name = main}
----222---<NSThread: 0x6000023d5840>{number = 4, name = (null)}
333和444因?yàn)樗梨i不能打印
print("----111---\(Thread.current)")
queue.sync { [weak self] in
print("----222---\(Thread.current)")
self?.queue.sync {
print("----3333---\(Thread.current)")
}
print("----44444---\(Thread.current)")
}
print("---555---\(Thread.current)")
----111---<_NSMainThread: 0x6000034dc0c0>{number = 1, name = main}
----222---<_NSMainThread: 0x6000034dc0c0>{number = 1, name = main}
555因?yàn)閝ueue.sync阻塞主線程不執(zhí)行,333和444是發(fā)生了死鎖
print("----111---\(Thread.current)")
DispatchQueue.main.async {
print("----2222---\(Thread.current)")
self.semaphore.signal()
}
print("----333---\(Thread.current)")
semaphore.wait()
print("----444---\(Thread.current)")
----111---<_NSMainThread: 0x6000005d00c0>{number = 1, name = main}
----333---<_NSMainThread: 0x6000005d00c0>{number = 1, name = main}
semaphore.wait()一直堵塞主線程氧急,沒被執(zhí)行完畢颗胡,導(dǎo)致主隊(duì)列中的async任務(wù)無(wú)法被調(diào)用
2、其他類型
print("----111---\(Thread.current)")
queue.sync { [weak self] in
print("----222---\(Thread.current)")
self?.queue.async {
print("----3333---\(Thread.current)")
}
print("----44444---\(Thread.current)")
}
print("---555---\(Thread.current)")
----111---<_NSMainThread: 0x600003fe05c0>{number = 1, name = main}
----222---<_NSMainThread: 0x600003fe05c0>{number = 1, name = main}
----44444---<_NSMainThread: 0x600003fe05c0>{number = 1, name = main}
---555---<_NSMainThread: 0x600003fe05c0>{number = 1, name = main}
----3333---<NSThread: 0x600003fbb480>{number = 9, name = (null)}
sync 無(wú)論在串行或者并發(fā)隊(duì)列中都會(huì)阻塞當(dāng)前線程吩坝,555后執(zhí)行毒姨,async將異步任務(wù)放到出行隊(duì)列中,需要等待前一個(gè)任務(wù)sync執(zhí)行完畢钉寝,在執(zhí)行自己
print("----111---\(Thread.current)")
DispatchQueue.main.async {
while true {
print("----true1---\(Thread.current)")
}
}
DispatchQueue.main.async {
while true {
print("----true2---\(Thread.current)")
}
}
print("----333---\(Thread.current)")
----111---<_NSMainThread: 0x600002e00380>{number = 1, name = main}
----333---<_NSMainThread: 0x600002e00380>{number = 1, name = main}
----true1---<_NSMainThread: 0x600002e00380>{number = 1, name = main}
無(wú)限的輸出----true1--弧呐,--true2--一直處于等待狀態(tài)
func performSelectedFunc() {
concurrentQueue.async {
print("----1----\(Thread.current)")
self.perform(#selector(self.test), with: nil, afterDelay: 2)
// RunLoop.current.run() //perform執(zhí)行完畢,runloop就關(guān)閉了嵌纲,放到perform前面無(wú)效
print("----3----\(Thread.current)")
}
}
@objc func test() {
print("---2-----\(Thread.current)")
}
----1----<NSThread: 0x600000a72e80>{number = 4, name = (null)}
----3----<NSThread: 0x600000a72e80>{number = 4, name = (null)}
子線程的runloop需要手動(dòng)開啟
for _ in 0 ... 1000 {
concurrentQueue.async { [unowned self] in
concurrentQueue.sync { [unowned self] in
self.ticketCount += 1
printCurrentThread(sort: "\(ticketCount)")
}
}
}
// 亂序輸出俘枫,且ticketCount的最終值小于1001
3、線程同步方案
1逮走、os_unfair_lock
var lock = os_unfair_lock()
for _ in 0 ... 100 {
concurrentQueue.async { [weak self] in
os_unfair_lock_lock(&lock)
self?.ticketCount += 1
print("--------\(self?.ticketCount)")
os_unfair_lock_unlock(&lock)
}
}
2鸠蚪、信號(hào)量
for _ in 0 ... 1000 {
concurrentQueue.async { [unowned self] in
self.threadSync()
}
}
func threadSync() {
semaphore.wait()
self.ticketCount += 1
printCurrentThread(sort: "\(ticketCount)")
semaphore.signal()
}
3、串行隊(duì)列
for _ in 0 ... 1000 {
concurrentQueue.async { [unowned self] in
self.threadSync()
}
}
func threadSync() {
queue.sync { [unowned self] in
self.ticketCount += 1
printCurrentThread(sort: "\(ticketCount)")
}
}
4师溅、柵欄
for _ in 0 ... 1000 {
concurrentQueue.async { [unowned self] in
self.threadSync()
}
}
func threadSync() {
concurrentQueue.async(flags: DispatchWorkItemFlags.barrier) { [unowned self] in
self.ticketCount += 1
printCurrentThread(sort: "\(ticketCount)")
}
}
4茅信、項(xiàng)目中的應(yīng)用場(chǎng)景
1、多個(gè)網(wǎng)絡(luò)請(qǐng)求都返回完畢墓臭,再統(tǒng)一刷新UI
func someRequstRefresView() {
let group = DispatchGroup()
func func1() {
self.concurrentQueue.async(group: group) {
Thread.sleep(forTimeInterval: 1)
print("----1---\(Thread.current)")
}
}
func func2() {
self.concurrentQueue.async(group: group) {
Thread.sleep(forTimeInterval: 1)
print("----2---\(Thread.current)")
}
}
func func3() {
self.concurrentQueue.async(group: group) {
Thread.sleep(forTimeInterval: 1)
print("----3---\(Thread.current)")
}
}
func1()
func2()
func3()
group.notify(queue: DispatchQueue.main) {
print("----notify---\(Thread.current)")
self.view.backgroundColor = .red
}
}
2蘸鲸、控制網(wǎng)絡(luò)請(qǐng)求返回的順序
func semaphorefunc() {
print("----begin---\(Thread.current)")
let semaphore = DispatchSemaphore.init(value: 1)
concurrentQueue.async {
semaphore.wait()
print("----1111---\(Thread.current)")
Thread.sleep(forTimeInterval: 1)
semaphore.signal()
}
concurrentQueue.async {
semaphore.wait()
print("----2222---\(Thread.current)")
semaphore.signal()
}
concurrentQueue.async {
semaphore.wait()
print("----3333---\(Thread.current)")
semaphore.signal()
}
print("----end---\(Thread.current)")
}
----begin---<_NSMainThread: 0x600001a985c0>{number = 1, name = main}
----end---<_NSMainThread: 0x600001a985c0>{number = 1, name = main}
----1111---<NSThread: 0x600001ad1140>{number = 43, name = (null)}
----2222---<NSThread: 0x600001ade600>{number = 5, name = (null)}
----3333---<NSThread: 0x600001a98c40>{number = 44, name = (null)}
3、數(shù)據(jù)計(jì)算線程安全
print("----begin---\(Thread.current)")
let semaphore = DispatchSemaphore.init(value: 1)
for _ in 0 ... 100 {
concurrentQueue.async { [weak self] in
semaphore.wait()
self?.ticketCount += 1
print("--------\(self?.ticketCount ?? 0)-----\(Thread.current)")
semaphore.signal()
}
}