文章目录
一、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的方法):
- waitUntilDone:在主线程中运行方法,wait表示是否阻塞这个方法的调用,如果为true则等待主线程中的运行方法结束。一般可用于在子线程中调用ui方法。此规则针对其他线程也适用。
- modes:线程模式,用到RunLoop的知识,如果modes参数为kCFRunLoopCommonModes的话可以结局滑动过程中图片赋值引起的页面卡顿问题,等.
- 此方法不能够自动回收线程,如果并发数量多,会建立大量子线程。
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方法执行;