先把常用的Demo放前面,方便查找,能满足绝大多数需求,各种理论后续再补充在后面。
1.延迟执行
let delay = DispatchTime.now() + .seconds(10)//计算需要开始的时间
print("添加了一个10秒后执行的任务")
DispatchQueue.main.asyncAfter(deadline: delay) {
//此处写入延迟执行的代码
print("延迟执行代码已开始执行")
sleep(3)
print("延迟执行代码已执行完毕")
}
2.线程安全锁(某一时刻只能一个线程调用)
swift3中废弃了dispatch_once,这里列举了可用的线程锁,两种方式如下
let lock = NSLock.init()
func funcMultiThread() {
//加锁方式1,类似于oc中@synchronized,互斥锁的一种
objc_sync_enter(self)
print("this is multi thread func begin")
sleep(4)
print("this is multi thread func ended")
objc_sync_exit(self)
//加锁方式2
lock.lock()
print("this is multi thread func begin")
sleep(4)
print("this is multi thread func ended")
lock.unlock()
}
3.单次执行(单例)
swift3中废弃了dispatch_once,GCD中没有只执行一次的方法,只能自己生成全局静态变量自己控制只调用一次。
但对于单例,可以用如下方式替换,相比OC中实现方式:
+ (instancetype)sharedInstance {
static LAPayRedPointManager *_sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
Swift中要简单得多,Demo如下
class FrankObj: NSObject {
static let shared = FrankObj()
var name:String = "frank"
}
使用上述方法,直接调用FrankObj.shared即可生成FrankObj的单例。经本人详细测试,该写法线程安全,多次创建只返回同一地址对象。
4.开辟子线程,完成后通知主线程
/// 异步执行,完毕通知主线程
func func1() {
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
DispatchQueue.global().async {
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
sleep(3)
print("异步代码执行完毕,准备通知主线程")
DispatchQueue.main.sync {
print("通知主线程啦")
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
}
}
}
5.三个任务,分别开辟三个线程,都执行完毕后通知主线程(group)
@IBAction func ibaButton1(_ sender: Any) {
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
let group = DispatchGroup();
let queue1 = DispatchQueue(label: "queue1")
queue1.async(group:group){
print("queue1开始任务")
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
sleep(4)
print("queue1结束任务")
}
let queue2 = DispatchQueue(label: "queue2")
queue2.async(group:group){
print("queue2开始任务")
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
sleep(8)
print("queue2结束任务")
}
let queue3 = DispatchQueue(label: "queue3")
queue3.async(group:group){
print("queue3开始任务")
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
sleep(30)
print("queue3结束任务")
}
group.notify(queue: DispatchQueue.main) {
print("上述任务都完成,通知主线程")
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
}
}
打印日志如下
在{number = 1, name = main}此执行异步代码,isMainThread == true
queue2开始任务
queue1开始任务
queue3开始任务
在{number = 3, name = (null)}此执行异步代码,isMainThread == false
在{number = 5, name = (null)}此执行异步代码,isMainThread == false
在{number = 4, name = (null)}此执行异步代码,isMainThread == false
queue1结束任务
queue2结束任务
queue3结束任务
上述任务都完成,通知主线程
在{number = 1, name = main}此执行异步代码,isMainThread == true
有时特殊需求,上面三个子线程又有一些异步耗时操作,需要在异步耗时操作完成之后再调用notify,可以对queue1做如下处理
let queue1 = DispatchQueue(label: "queue1")
queue1.async(group:group){
print("queue1开始任务")
print("在\(Thread.current)此执行异步代码,isMainThread == \(Thread.isMainThread)")
queue1.async(execute: {
group.enter()//这行很重要
print("这是queue1的子线程中的log,子线程开始")
sleep(6)
print("这是queue1的子线程中的log,子线程结束")
group.leave()
})
print("queue1结束任务")
}
这样就能保证queue子线程完成之前不会回调notify,group.leave()之后,才会调用Notify
6.有两个任务,想在任务1执行完毕后,执行任务2。任务比较少,如果利用group有点大材小用,可以用下面这几种方式做线程依赖
let queue1 = DispatchQueue(label: "queue1")
// 任务1
let work1 = DispatchWorkItem {
print("开始work1")
sleep(4)
print("结束work1")
}
// 任务2
let work2 = DispatchWorkItem {
print("开始work2")
sleep(2)
print("结束work2")
}
// 第一种绑定方式
work1.notify(queue: queue1) {
// 执行2
work2.perform()
}
// 第二中绑定方式
work1.notify(queue: queue1, execute: work2)
// 第三种可以直接不创建work2,在闭包中执行work的工作
work1.notify(queue: queue1) {
print("开始闭包中 work2")
sleep(2)
print("结束闭包中 work2")
}
// 执行任务:
// 方式1:任务放在队列中并执行
queue1.async(execute: work1)
// 方式2:如果不指定队列,会在当前的队列中执行,如果在主线程中执行会造成线程阻塞
work1.perform()
7.一共有五个任务,abcde,其中ab并发进行,ab都执行完毕之后执行C,C执行完毕之后DE并发执行。当然,可以用上述Group进行,但GCD中封住了更方便的方法,Barrier,如下
func func4() {
let queue = DispatchQueue(label: "queuename", attributes: .concurrent) //并发队列
queue.async {
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
print("开始第1个任务")
sleep(4)
print("结束第1个任务")
}
queue.async {
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
print("开始第2个任务")
sleep(1)
print("结束第2个任务")
}
queue.sync(flags: .barrier,execute:{
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
print("开始执行Barrier中的任务")
sleep(9)
print("barrier中的任务执行完毕")
})
queue.async {
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
print("开始第3个任务")
sleep(2)
print("结束第3个任务")
}
queue.async {
print("当前是\(Thread.current),isMainThread == \(Thread.isMainThread)")
print("开始第4个任务")
sleep(4)
print("结束第4个任务")
}
}
打印结果如下
当前是{number = 4, name = (null)},isMainThread == false
当前是{number = 3, name = (null)},isMainThread == false
开始第2个任务
开始第1个任务
结束第2个任务
结束第1个任务
当前是{number = 3, name = (null)},isMainThread == false
开始执行Barrier中的任务
barrier中的任务执行完毕
当前是{number = 3, name = (null)},isMainThread == false
当前是{number = 5, name = (null)},isMainThread == false
开始第3个任务
开始第4个任务
结束第3个任务
结束第4个任务
8.工程中有N个任务,依次加入队列。既要控制最大并发数,又要充分利用性能,这时候需要用到信号量的概念。简单说,信号量就是在多线程中设置最大并发数,达到了,其余的线程等待;未达到,从线程队列中找下一个加进来。
swift:
let group = DispatchGroup()
let semaphore = DispatchSemaphore(value: 10)
let queue = DispatchQueue.global()
for i in 0 ... 100 {
//由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,从而semaphore-1.当循环10此后,semaphore等于0,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal 才会继续执行
semaphore.wait()
queue.async(group: group){
print("\(i)")
sleep(3)
semaphore.signal()
}
}
OC:
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 创建信号量,并且设置值为10
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++) {
// 由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,从而semaphore-1.当循环10此后,semaphore等于0,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal 才会继续执行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{ NSLog(@"%i",i);
sleep(2);
// 每次发送信号则semaphore会+1,
dispatch_semaphore_signal(semaphore);
});
}