队列的创建和获取:
// 串行队列
let serialQueue = DispatchQueue(label: "www.google.com")
// 并行队列
let concurrentQueue = DispatchQueue(label: "www.google.com1", attributes: .concurrent)
// 主队列
let mainQueue = DispatchQueue.main
// 全局并发队列
let globalQueue = DispatchQueue.global()
// 指定队列优先级
let con = DispatchQueue(label: "conQueue", qos: .userInitiated)
// 串行队列、同步执行 ---->> 在当前线程顺序执行
func serialQueueSync() {
print("begin")
for i in 0...8 {
serialQueue.sync {
print(i, Thread.current)
}
}
print("end")
}
// 串行队列、异步执行 ---->> 在新线程顺序执行
func serialQueueAsync() {
print("begin")
for i in 0...8 {
serialQueue.async {
print(i, Thread.current)
}
}
print("end")
}
// 并行队列、同步执行 ---->> 在当前线程顺序执行
func concurrentQueueSync() {
print("begin")
for i in 0...180 {
concurrentQueue.sync {
print(i, Thread.current)
}
}
print("end")
}
// 并行队列、异步执行 ---->> 在新线程乱序执行
func concurrentQueueAsync() {
print("begin")
for i in 0...8 {
concurrentQueue.async {
print(i)
}
}
print("end")
}
// 延时执行
func queueDelay() {
print(Date())
Thread.sleep(forTimeInterval: 2)
print(Date())
// 延迟执行
mainQueue.asyncAfter(deadline: .now() + 2) {
print(Date())
print(Thread.current)
}
print(Date())
}
// 线程间通讯
func communicateBetweenQueue() {
globalQueue.async {
let a = "a" // 假设为延时操作,比如下载图片
print(Thread.current)
self.mainQueue.async {
print(a, Thread.current)
}
}
}
// 线程安全
func threadSafty() {
var names = ["li"]
for i in 0...10 {
concurrentQueue.async {
// 加锁 同OC @synchronized(self) {}
objc_sync_enter(self)
names.append("\(i)")
print(names)
objc_sync_exit(self)
}
}
// 或利用阻塞式的特点
for x in 11...20 {
concurrentQueue.async(flags: .barrier, execute: {
names.append("\(x)")
print(names)
})
}
}
// 阻塞式队列
func barrier() {
print("begin")
for i in 40...60 {
concurrentQueue.async {
if i == 40 {
Thread.sleep(forTimeInterval: 1)
}
print(i)
}
}
concurrentQueue.async(flags: .barrier) {
print("barrier1", Thread.current)
}
for i in 30...39 {
concurrentQueue.async {
print(i)
}
}
concurrentQueue.async(flags: .barrier) {
print("barrier2", Thread.current)
}
for i in 0...29 {
concurrentQueue.async {
print(i)
}
}
print("end")
}
// 信号量
func dispatchSemaphore() {
let semaphore = DispatchSemaphore(value: 1)
concurrentQueue.async {
_ = semaphore.wait(timeout: .distantFuture)
print(1, Date())
sleep(1)
semaphore.signal()
}
concurrentQueue.async {
_ = semaphore.wait(timeout: .distantFuture)
print(2, Date())
sleep(2)
semaphore.signal()
}
concurrentQueue.async {
_ = semaphore.wait(timeout: .distantFuture)
print(3, Date())
sleep(3)
semaphore.signal()
}
print("semaphore")
}
// 队列组
func dispatchGroup() {
// 队列组
let group = DispatchGroup()
group.enter()
concurrentQueue.async {
sleep(1)
print(1)
group.leave()
}
group.enter()
concurrentQueue.async {
// sleep(2)
print(2)
group.leave()
}
group.notify(queue: mainQueue) {
print(3)
}
}
- 如何设计一个线程安全的字典或数组?
在编码过程中,对数组进行多线程写入,会引起崩溃:
var names = ["li"]
for i in 0...10 {
concurrentQueue.async {
names.append("\(i)")
print(names)
}
}
采用部分代码加锁可解决这一问题:
var names = ["li"]
for i in 0...10 {
concurrentQueue.async {
// 加锁 同OC @synchronized(self) {}
objc_sync_enter(self)
names.append("\(i)")
print(names)
objc_sync_exit(self)
}
}
在实践操作中,对数组进行多线程的读取并不会引起崩溃
var names = ["li", "wang", "sun", "zhao", "qiao", "zhang", "gai", "tu", "yi", "fei", "huo"]
for a in 0...10 {
concurrentQueue.async {
print(a, names[a])
}
}
如何设计一个线程安全的字典或数组
实验证明多线程的读取数组或字典是不会引起崩溃的
多线程的写入字典或数组会引起崩溃
- 读取时保证没有别的线程在写
- 写入时保证没有别的线程在写或读
当满足上面两个要求时可实现线程安全的字典或数组
- 利用阻塞式的特点,我们将所有的写入操作写入阻塞式操作中,即可满足条件