当前位置: > > > Swift - 多线程实现方式(1) - Thread

Swift - 多线程实现方式(1) - Thread

1,Swift继续使用Object-C原有的一套线程,包括三种多线程编程技术:
(1)Thread
(2)Cocoa Operation(Operation和OperationQueue)
(3)Grand Central Dispath(GCD)

2,本文着重介绍Thread
Tread在三种多线程技术中是最轻量级的,但需要自己管理线程的生命周期和线程同步。线程同步对数据的加锁会有一定的系统开销。(本文代码已全部更新至Swift3)

3,Thread的两种创建方式
(1)直接创建线程并且自动运行线程
(2)先创建一个线程对象,然后手动运行线程,在运行线程操作之前可以设置线程的优先级等线程信息。
import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //方式1:使用类方法
        Thread.detachNewThreadSelector(#selector(ViewController.downloadImage),
                                       toTarget: self, with: nil)
        
        //方式2:实例方法-便利构造器
        let myThread = Thread(target: self,
                              selector: #selector(ViewController.downloadImage),
                              object: nil)
        myThread.start()
    }
    
    //定义一个下载图片的方法,线程调用
    func downloadImage(){
        let imageUrl = "http://hangge.com/blog/images/logo.png"
        let data = try! Data(contentsOf: URL(string: imageUrl)!)
        print(data.count)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

4,线程同步
线程同步方法通过锁来实现,每个线程都只用一个锁,这个锁与一个特定的线程关联。下面演示两个线程之间的同步。
import UIKit

class ViewController: UIViewController {
    
    //定义两个线程
    var thread1:Thread?
    var thread2:Thread?
    
    //定义两个线程条件,用于锁住线程
    let condition1 = NSCondition()
    let condition2 = NSCondition()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        thread2 = Thread(target: self, selector: #selector(ViewController.method2),
                         object: nil)
        thread1 = Thread(target: self, selector: #selector(ViewController.method1),
                         object: nil)
        thread1?.start()
    }
    
    //定义两方法,用于两个线程调用
    func method1(sender:AnyObject){
        for i in 0 ..< 10 {
            print("Thread 1 running \(i)")
            sleep(1)
            
            if i == 2 {
                thread2?.start() //启动线程2
                
                //本线程(thread1)锁定
                condition1.lock()
                condition1.wait()
                condition1.unlock()
            }
        }
        
        print("Thread 1 over")
        
        //线程2激活
        condition2.signal()
    }
    
    //方法2
    func method2(sender:AnyObject){
        for i in 0 ..< 10 {
            print("Thread 2 running \(i)")
            sleep(1)
            
            if i == 2 {
                //线程1激活
                condition1.signal()
                
                //本线程(thread2)锁定
                condition2.lock()
                condition2.wait()
                condition2.unlock()
            }
        }
        
        print("Thread 2 over")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
输出结果:

评论7
  • 7楼
    2017-08-07 14:10
    lokizero00

    问题是,怎么区别哪个锁是thread1的,哪个是thread2的。如果我代码里吧condition的顺序调换呢?

    站长回复

    Condition不是锁,而是条件。一个锁可能关联一个或多个条件。wait将线程休眠,signal将线程唤醒。你用哪个condition无所谓,关键看代码逻辑。

     比如代码里把condition顺序调换(原来用condition1的换成condition2,原来用condition2的换成condition1),那么执行效果还是和原来是一模一样的。 
    使用Condition不是说我在线程外面随意控制这个线程暂停还是运行,而是为了让多个线程某些情况下不会同时运行。

  • 6楼
    2017-07-27 16:47
    lokizero00

    //定义两个线程条件,用于锁住线程
    let condition1 = NSCondition()
    let condition2 = NSCondition()
    创建了条件 没看到 怎么关联NSThread

    一样的问题,如果照你的说法,我不是无法精确的控制某个线程了吗?如果我想暂停thread1,那我应该用哪个condition去暂停呢?

    站长回复

    代码里有啊:

    if i == 2 {
      thread2?.start() //启动线程2
                     
       //本线程(thread1)锁定
      condition1.lock()
      condition1.wait()
      condition1.unlock()
    }

    thread1在运行到 i==2 的时候就暂停了,然后等thread2那边解锁。

  • 5楼
    2017-03-17 10:58
    sss

    跟java的可重入锁使用很相似。

  • 4楼
    2016-04-25 15:07
    willingseal

    写的不错,简单易懂

    站长回复

    谢谢你的支持与鼓励,欢迎常来看看。

  • 3楼
    2015-09-25 10:33
    linchan

    请问如果把一些启动后线程对象放进数组,怎么在必要的时候暂停,然后又在必要的时候启动这些线程的执行呢?(我是想在TableView等实现如安卓中滚动时图片等数据暂停加载,滚动停止后继续加载数据)如果NSThread无法做到,用NSOperation和NSOperationQueue能不能做到,又该怎么实现呢?

    在NSThread线程中,我能不能通过遍历线程对象数组,把每一个线程对象用NSCondition锁定,等需要时在逐一解锁呢?

    站长回复

    这个用NSOperation和NSOperationQueue是可以做到的。这几天比较忙,我下周会抽空写篇相关的文章。

  • 2楼
    2015-09-25 10:28
    linchan

    请问如果把一些启动后线程对象放进数组,怎么在必要的时候暂停,然后又在必要的时候启动这些线程的执行呢?(我是想在TableView等实现如安卓中滚动时图片等数据暂停加载,滚动停止后继续加载数据)如果NSThread无法做到,用NSOperation和NSOperationQueue能不能做到,又该怎么实现呢?

    站长回复

    这个用NSOperation和NSOperationQueue是可以做到的。这几天比较忙,我下周会抽空写篇相关的文章。

  • 1楼
    2015-09-17 15:08
    zyg

    //定义两个线程条件,用于锁住线程
    let condition1 = NSCondition()
    let condition2 = NSCondition()
    创建了条件 没看到 怎么关联NSThread

    站长回复

    这个NSCondition条件不是说创建完毕后要硬性关联个NSThread。而是线程方法内部自己先去取得这个锁,如果没有,则wait,释放锁,直到有其它线程唤醒这个锁。