Swift多线程:使用Thread进行多线程间通讯,协调子线程任务

Swift的多线程技术其实和Objective-C没有区别。Thread是三种正常程序员会使用的多线程中最轻量级的,每一个Thread对象代表着一个线程,但是需要自己管理线程的生命周期和线程的同步。线程同步对数据的加锁会有一定的开销。

哪三种正常程序员会使用的多线程方案,问这个的同学,你,出去~ 前面写了辣么多,Operation、GCD、Thread,都忘啦?

image.png

如果要是较真,还有一个多线程技术,叫做pthread。我们会在最后最后稍微说一下它。但是它绝对不是正常程序员现在还需使用的多线程方案。说完这句话不知道会不会被喷死

1. Thread的三种建立方式

以下所有的代码都是使用陈旧的Swift 3.0编写。

对,你没看错。陈旧的Swift 3.0。 昨天刚刚看到新闻,说Swift 5.0 都开始了。听到这个消息的时候,内心是五味杂陈的,有点点为Swift担心了。尼玛4.0 刚发布,5.0就开始了。
所以坊间才有笑话说,学习iOS开发需要熟练使用Swift1.0 , Swift2.0 ,Swif 2.2...四种语言之类的。

1.1 使用类方法创建,自动运行

一种是带Selector,一种不带。

Thread.detachNewThread {
    print("A new thread,name:\(Thread.current)")
}


//带一个Selector
       Thread.detachNewThreadSelector(#selector(threadPrint), toTarget: self, with: nil)

通过这种方法创建的thread会自动运行。

1.2 实用构造方法创始化,需手动运行

这里可是使用两种方法直接创建Thread,并运行。

Thread(block: <#T##() -> Void#>)
Thread(target: <#T##Any#>, selector: <#T##Selector#>, object: <#T##Any?#>)

下面是个例子,这种方法创建的thread需要手动start运行

   let customThread = Thread(target: self, selector: #selector(threadPrint), object: nil)
    customThread.start()

1.3 使用NSObject的拓展方法

任何继承自NSObject的都可以很容易的通过这种方式调用点成方法。

来,我们一起来看一下源文件:

extension NSObject {

    
    open func performSelector(onMainThread aSelector: Selector, with arg: Any?, waitUntilDone wait: Bool, modes array: [String]?)

    open func performSelector(onMainThread aSelector: Selector, with arg: Any?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    open func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool, modes array: [String]?)

    @available(iOS 2.0, *)
    open func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    open func performSelector(inBackground aSelector: Selector, with arg: Any?)
}

2. Thread的基本使用

Thread的基本使用相当简单,和GCD基本上差不多。也有启动、暂停、取消、阻塞、设置优先级等等。

方法 作用
start 启动
cancel 暂停
exit 取消
sleep 阻塞

Thread的常用属性

名称 用途
name 给线程命名,方便查找
stackSize 栈区大小,看看线程在栈区占了多大空间
isMainThread 是否是主线程
qualityOfService 服务质量,iOS8.0推出,为了取代优先级。
  • 说明:thread设置了start后,其实并不是马上就开始运行了。实质上是放进了可调度线程池,等待被CPU调用。线程执行结束之前,状态可能会在就绪状态 和 运行状态 之间来回的切换
    就绪状态 和 运行状态 之间的状态切换由CPU来完成,程序员无法干涉。

  • 阻塞:正在运行thread可以通过sleep的方式来阻塞线程的执行。

  • 退出:thread在执行完毕之后会自动退出。如果执行了exit,线程会强制退出。有几点需要注意一下:

    • 不要在主线程中调用啊,会让UI线程退出的。退出之后看你怎么搞!
    • 退出之后,这个线程剩下的所有代码都不会被执行。
    • 调用这个方法之前,一定要注意释放之前由C语言创建的对象,不然会造成内存泄漏等问题。
  • 取消:这个cancel和GCD一样的啦,并没有真证的取消线程,只是打了一个标志。取消需要自己的实现。也就是在大人物开始之前,先判断一下这个标志位的状态。要是从来都没写过这个标志位的状态判断,那cancel了也是白瞎。

3. 使用NSCondition实现线程间通讯

大家还记得GCD中的信号量(semaphore)嘛?不记得话看看喽,传输门:Swift多线程:GCD进阶,单例、信号量、任务组 。Thread里面的NSCondition和这个有点像。

这个玩意一共就四个方法,我们索性都来看看:

方法名称 作用
wait 使线程处于等待状态
wait(until limit: Date) -> Bool 在给定的时间到达时仍未有信号量出现, 就自动继续了
signal 唤醒线程
broadcast 唤醒所有等待线程

NSCondition实现了NSLocking协议,所以它本身也有lock和unlock方法。配合在一起可以解决线程同步的问题,只要在线程开始时加锁,取得资源后释放锁即可。使用时把需要加锁的代码放到lockunlock之间就可以了。

主要不要把什么乱七八糟的都往加锁代码里面放,放在这个里面的应该是抢占资源的读取和修改。不然一个线程执行的时候另一个线程就一直在等待,那还要多线程干哈玩意?!

我们搞个例子来看看。

需求:
1,模拟下载五张图片、五篇文章;
2,图片下载了两张之后,暂停下载,转而开启文章下载;
3,下载三篇文章之后,暂停下载,转而继续下载剩下的三张图片。
4,图片下载完成后,下载完成剩下的两篇文章。
说了是模拟啊,所以下载过程就直接print了噢。

class ViewController: UIViewController {
    var downImages: Thread?
    var downArticles: Thread?
    
    let imageCondition = NSCondition()
    let articleCondition = NSCondition()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        downImages = Thread(target: self, selector: #selector(downloadImages), object: nil)
        downArticles = Thread(target: self, selector: #selector(downloadArticles), object: nil)
        downImages?.start()
        
    }
    
    @objc private func threadPrint() {
        Thread.sleep(forTimeInterval: 2)
        print("After 2 seconds, I have been performed. I am \(Thread.current)")
    }
    
    @objc fileprivate func downloadImages() {
        for index in 1...5 {
            print("Downloading No.\(index) image.")
            Thread.sleep(forTimeInterval: 1)
            
            if index == 2 {
                //start downArticles.开启下载文章的线程
                downArticles?.start()
                
                //Lock the image thread.加锁,让下载图片的线程进入等待状态
                imageCondition.lock()
                imageCondition.wait()
                imageCondition.unlock()
            }
        }
        print("All images have been completed.")
        
        //Signaling the article when all images completed.
//        等图片都下载完成之后,激活下载文章的进程
        articleCondition.signal()
    }
    
    @objc fileprivate func downloadArticles() {
        for index in 1...5 {
            print("The No.\(index) article will be downloading.")
            Thread.sleep(forTimeInterval: 1)
            if index == 3 {
                //Signaling the image thread, let it continue to down.
                //激活图片的线程,让它继续下载图片
                imageCondition.signal()
                
                //Lock the article thread.加锁,让下载文章的线程进入等待状态
                articleCondition.lock()
                articleCondition.wait()
                articleCondition.unlock()
                
            }
        }
        print("There are 5 articles.")
        
    }
}

我们开一下最终的打印结果:

image.png

好了。最后再说一下基本上没人用的pthread

4. pthread

其实不知道这个多线程的技术现在还有谁会在用,除了面试可能会偶尔问一下这个名词。
pthread是POSIX thread的简写。表示跨平台的线程接口。

为了能够写Demo,非典型技术宅在浩瀚的Google海洋中游荡了很久,然后,然后,然后放弃了...

怎么能这么不坚持呐,在OC时代曾经还是能写出来创建的。于是去看苹果手册,然后,然后,然后放弃了...

Threading Programming Guide 。这里倒是提到了POSIX thread ,还让人家去看pthread man page。但是,明显链接被删除了。

苹果爸爸。。。好想锤你小胸口。好吧,放弃了。

最后,所有的代码都放在这里了:gitHub 下载后给颗Star吧~ 么么哒~(~o ̄3 ̄)~ 爱你们~


iOS多线程系列之一:Operation基础操作,按优先级加载图片
iOS多线程系列之二:Operation实例,异步加载CollectionView图片
iOS多线程系列之三:使用GCD实现异步下载图片
iOS多线程系列之四:GCD进阶,单例、信号量、任务组
iOS多线程系列之五:使用Thread进行多线程间通讯,协调子线程任务

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容