iOS多线程---Thread

一、Thread简介

Thread是苹果官方提供的,使用起来比pthread更加面向对象,简单易用,可以直接操作线程对象。
Thread也需要程序员自己管理线程的生命周期。

二、Thread方法介绍

1. Thread各个属性的意义

threadPriority :线程优先级(double)0.0~1.0,默认0.5,优先级和执行顺序成正比
name :线程名字
stackSize: 线程栈大小,默认主线程1m ,子线程512k,次属性可读写,但是写入大小必须为4k的倍数,最小为16k
isMainThread: 是否是主线程
executing :是否正在执行
finished :是否已经完成
cancelled: 是否已经取消

2. Thead实例方法

public init():没有给Thread 加 selector 的方法,目测是用来继承然后重写main方法来用的
public convenience init(target: Any, selector: Selector, object argument: Any?) 通过selector初始化
open func main() 主方法,用于子类继承重写
open func start() 开始线程
open func cancel() 取消线程

3. Thead类方法和属性,作用域:当前线程

属性
class var current: Thread { get } : 返回当前线程
class var callStackReturnAddresses: [NSNumber] { get }: 返回当前线程访问的堆栈信息
class var callStackSymbols: [String] { get }: 返回一堆十六进制的地址
class var isMainThread: Bool { get }: 是否是主线程

方法
class func detachNewThreadSelector(_ selector: Selector, toTarget target: Any, with argument: Any?): 开辟一个新的线程
class func sleep(until date: Date) :休眠到什么时候(具体日期)
class func sleep(forTimeInterval ti: TimeInterval): 休眠一段时间单位秒
class func exit(): 结束当前线程
class func threadPriority() -> Double: 返回当前线程优先级
class func setThreadPriority(_ p: Double) -> Bool: 设置当前线程优先级 0.0~1.0
class func isMultiThreaded() -> Bool: 返回当前线程是否是主线程
class var main: Thread { get } 返回主线程

4. iOS中隐式创建线程的方法(NSObject的方法):

  1. waitUntilDone:在主线程中运行方法,wait表示是否阻塞这个方法的调用,如果为true则等待主线程中的运行方法结束。一般可用于在子线程中调用ui方法。此规则针对其他线程也适用。
  2. modes:线程模式,用到RunLoop的知识,如果modes参数为kCFRunLoopCommonModes的话可以结局滑动过程中图片赋值引起的页面卡顿问题,等.
  3. 此方法不能够自动回收线程,如果并发数量多,会建立大量子线程。
func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool)
func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool, modes array: [String]?)

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

func performSelector(inBackground aSelector: Selector, with arg: Any?)

// 延迟执行,这里用到runloop的东西
func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval)
func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval, inModes modes: [RunLoop.Mode])
// 取消线程队列中还没有执行的方法
class func cancelPreviousPerformRequests(withTarget aTarget: Any)
class func cancelPreviousPerformRequests(withTarget aTarget: Any, selector aSelector: Selector, object anArgument: Any?)

三、Thread使用

1. 创建线程任务

    func threadAction() {
        // 1. 创建线程
        let thread = Thread.init(target: self, selector: #selector(run), object: nil)
        // 2. 启动线程
        thread.start()// 线程一启动,就会在线程thread中执行self的run方法
    }
    
    @objc func run() {
        // 打印当前线程
        print(Thread.current)
    }

2. 线程安全

var ticketCount = 0
    /// 初始化票数量、卖票窗口(线程安全)、并开始卖票
    func initTicketStatusSave() {
        // 1. 设置剩余票为 50
        self.ticketCount = 50;
        
        // 2. 设置火车票售卖窗口的线程1
        let ticketFirst = Thread.init(target: self, selector: #selector(saleTicketSafe), object: nil)
        ticketFirst.name = "售票窗口1"
        
        // 3. 设置火车票售卖窗口的线程2
        let ticketSecond = Thread.init(target: self, selector: #selector(saleTicketSafe), object: nil)
        ticketSecond.name = "售票窗口2"
        
        // 4. 开始售票
        ticketFirst.start()
        ticketSecond.start()
    }
    
    /// 售票(线程安全)
    @objc func saleTicketSafe() {
        while (true) {
            // 互斥锁
            objc_sync_enter(self)
            // 如果还有票,继续售卖
            if (self.ticketCount > 0) {
                self.ticketCount -= 1
                print("剩余票数:\(self.ticketCount) 窗口:\(Thread.current.name ?? "nil")")
                Thread.sleep(forTimeInterval: 0.2)
            }
            //如果已卖完,关闭售票窗口
            else {
                print("所有票均已售完")
                return
            }
            objc_sync_exit(self)
        }
    }

3. 线程间通信

线程间通信:即从一个线程进入到另一个线程继续执行任务或者是传递参数(如从子线程回到主线程)

示例演示:在主线程中先创建一个子线程下载图片,当图片下载完成后又切换到主线程设置图片的操作。

private func downImage() {
        // 程序启动后开子线程下载图片,图片下载完成之后回到主线程设置图片
        Thread.detachNewThreadSelector(#selector(downloadImage), toTarget: self, with: nil)
        
    }
    
    @objc private func downloadImage() {
        // 1.获得要下载图片的url
        guard let url = URL(string: "http://p9.qhimg.com/t014d1bd470cb60ac6e.jpg")
        else {
            return
        }
        // 2.把url地址指向资源的二进制下载到本地
        guard let imageData = try? Data(contentsOf: url) else {
            return
        }
        // 3.把二进制数据转换为图片
        let image = UIImage(data: imageData)
        // 4.打印查看当前线程(应该是在子线程中下载图片)
        print("当前线程为\(Thread.current)")
        // 5.线程间通信
        // 方法一
        self.performSelector(onMainThread: #selector(showImage(_:)), with: image, waitUntilDone: true)
        // 方法二
//        imageView.performSelector(onMainThread: #selector(setImage(_:)), with: image, waitUntilDone: true)
    }
    
    @objc private func showImage(_ image: UIImage) {
        // 设置图片
        imageView.image = image
        // 打印查看设置图片操作的线程
        print("处理UI刷新操作的线程\(Thread.current)")
    }

四、 一些注意点:

  • 在子类重写父类的方法中,start 方法先于main方法执行;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值