2、Thread —— swift3.0

Swift3.0 中的 Thread 类
其实就是 NSThread

import CoreFoundation
import CoreGraphics
import Darwin
import Darwin.uuid
import Foundation

/*  NSThread.h
    Copyright (c) 1994-2015, Apple Inc. All rights reserved.
*/
// 在 swift 3.0 中  NSThread 被修改我 Thread
public class Thread : NSObject {

    // 获取当前执行的线程
    // 通过当前线程的 number 属性, number == 1 的时候为单线程, number > 1 的时候是多线程, number 的数字没有很多的参考价值
    public class func current() -> Thread

    // 分离出新线程, 类方法, (直接创建一个线程对象,并开启线程)
    // 当我们给需要在新线程中执行某方法的时候可以用这个方法
    public class func detachNewThreadSelector(_ selector: Selector, toTarget target: AnyObject, with argument: AnyObject?)

    // 判断是否是多线程
    public class func isMultiThreaded() -> Bool

    
    public var threadDictionary: NSMutableDictionary { get }

    // 线程睡(指定时间)
    public class func sleep(until date: Date)
    // 指定时间间隔
    public class func sleep(forTimeInterval ti: TimeInterval)

    // 退出线程
    public class func exit()


    // 线程的优先级处理
    // 线程的级别
    public class func threadPriority() -> Double
    // 设置线程级别
    public class func setThreadPriority(_ p: Double) -> Bool

    @available(iOS 4.0, *)
    // 设置线程的级别, 已经被弃用,请用下面的服务质量
    public var threadPriority: Double // To be deprecated; use qualityOfService below

    
    @available(iOS 8.0, *)
    // 服务质量
    public var qualityOfService: QualityOfService // read-only after the thread is started

    
    @available(iOS 2.0, *)
    // 调用堆栈返回的地址
    public class func callStackReturnAddresses() -> [NSNumber]

    @available(iOS 4.0, *)
    // 线程的符号
    public class func callStackSymbols() -> [String]

    
    @available(iOS 2.0, *)
    // 线程名称
    public var name: String?

    
    @available(iOS 2.0, *)
    // 获取栈内存大小 , 默认 512k
    public var stackSize: Int

    
    @available(iOS 2.0, *)
    // 判断是否是主线程
    public var isMainThread: Bool { get }

    @available(iOS 2.0, *)
    // 判断当前线程是否是主线程
    public class func isMainThread() -> Bool // reports whether current thread is main

    @available(iOS 2.0, *)
    // 获取主线程
    public class func main() -> Thread

    
    @available(iOS 2.0, *)
    // 初始化方法
    public init()

    @available(iOS 2.0, *)
    // 便利初始化方法
    public convenience init(target: AnyObject, selector: Selector, object argument: AnyObject?)

    
    // 线程状态的判断
    @available(iOS 2.0, *)
    // 线程是否执行
    public var isExecuting: Bool { get }

    @available(iOS 2.0, *)
    // 线程是否完成
    public var isFinished: Bool { get }

    @available(iOS 2.0, *)
    // 线程是否取消
    public var isCancelled: Bool { get }

    
    @available(iOS 2.0, *)
    // 取消线程
    public func cancel()

    
    @available(iOS 2.0, *)
    // 开始线程
    public func start()

    
    @available(iOS 2.0, *)
    // 线程主体方法,这个方法一般是用来重写的
    public func main() // thread body method
}


// 通知
extension NSNotification.Name {

    // 将要变成多线程
    public static let NSWillBecomeMultiThreaded: NSNotification.Name
    // 已经变成单线程
    public static let NSDidBecomeSingleThreaded: NSNotification.Name
    // 线程将要推出
    public static let NSThreadWillExit: NSNotification.Name
}


// NSObject 的类扩展
// 意味着所有的 NSObject 对象都可以使用下面的方法
extension NSObject {

    // 在主线程执行某方法
    public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)
    // 在主线程执行某方法
    public func performSelector(onMainThread aSelector: Selector, with arg: AnyObject?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    // 在某个线程执行某方法
    public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool, modes array: [String]?)

    @available(iOS 2.0, *)
    // 在某个线程执行某方法
    public func perform(_ aSelector: Selector, on thr: Thread, with arg: AnyObject?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    // 在后头执行选中的方法
    public func performSelector(inBackground aSelector: Selector, with arg: AnyObject?)
}

上面贴头文件纯属个人喜好,本人简单翻译为的是后期的被查,解决英文不好的毛病。


1、判断当前线程数可以知道是否是多线程。

Thread.current() number 为 1 的时候是主线程,线程数不为1 就为多线程。数子没有意义。

print(Thread.current())

打印结果
<NSThread: 0x7ff791402120>{number = 1, name = main}

objc

[NSThread currentThread];
NSLog(@"%@", [NSThread currentThread]);

打印结果:
2016-06-21 19:28:24.644 Thread-Objc[4072:1165465] <NSThread: 0x7f9e73405100>{number = 1, name = main}

使用函数判断是否是多线程

if Thread.isMultiThreaded() {
     print("是单线程执行")
}

objc

if (![NSThread isMultiThreaded]) {   
        NSLog(@"中是单线程!");
}

2、线程的创建

 // 创建一个线程对象 
 let thread1 = Thread(target: self, selector: #selector(longOperation), object: "thread1")

 //  线程默认是不会启动的
 //  必须我们手动启动
 thread1.start()

// 线程执行的的方法
func longOperation(sender: AnyObject){
   print(sender)  // sender == thread1 
     for i in 0...50000 {
     print("\(i )" + "\(Thread.current())")
  }
}

objc

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(longOperation:) object:@"newThread"];
[thread start];

- (void)longOperation:(NSObject *)sender {
    
    NSLog(@"%@", sender);   // sender == newThread
    NSLog(@"%@", [NSThread currentThread]);
}
// 这样就创建了一个线程对象
// 这样创建的线程操作性太小
// 我们一般会使用上面的方法
let thread  = Thread()

通过 Thread 直接分离(创建)一个线程执行某个方法。
使用这种方式创建的线程,线程是直接启动的

Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "newThread")

// 线程执行的方法
func longOperation(sender: AnyObject){
    print(sender)   // sender ==  newThread
   for i in 0...50 {
     print("\(i )" + "\(Thread.current())") 
    }
}
[NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self withObject:@"newThread"];
- (void)longOperation:(NSObject *)sender {

    NSLog(@"%@", sender);   // sender == newThread
    NSLog(@"%@", [NSThread currentThread]);
}

打印结果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] <NSThread: 0x7f80e2c7a7b0>{number = 2, name = (null)}

一个方法里面的内容只能在一个线程里面执行,block 或闭包除外。

使用 NSObject 的方法直接在后台线程执行某方法
(实际上也是创建一个新的线程对象,并启动线程)

self.performSelector(inBackground: #selector(longOperation), with: "newThread")

// 线程执行的方法
func longOperation(sender: AnyObject){
    print(sender)
    for i in 0...50 {
     print("\(i )" + "\(Thread.current())")
  }
}
[self performSelectorInBackground:@selector(longOperation:) withObject:@"newThread"];
- (void)longOperation:(NSObject *)sender {

    NSLog(@"%@", sender);   // sender == newThread
    NSLog(@"%@", [NSThread currentThread]);
}

打印结果
2016-06-21 19:46:56.170 Thread-Objc[4351:1183028] newThread
2016-06-21 19:46:56.171 Thread-Objc[4351:1183028] <NSThread: 0x7f80e2c7a7b0>{number = 2, name = (null)}

这种方式表明:
任何 NSObject 对象都可以开启子线程。(都具有开启线程的能力)

3、线程属性

线程名称

// 线程名称
public var name: String?

线程的名称通常在大的商业应用中,希望应用程序上架后,捕获到用户使用崩溃的一些场景。
如果知道程序在哪个线程中崩溃,能够辅助排错。
如果线程非常多,而且在调试的时候可以起到辅助作用。

线程堆栈大小

Thread.current().stackSize

// 调整大小
Thread.current().stackSize = 1024 * 1024 

线程的栈空间大小是 统一都是 512 k, 大小是可以修改。

在以前的版本中 主线程是 1024k, 其他线程是 512k ,大小是不能修改。

线程的优先级

// 线程的优先级 0 到1.0 , 1 的优先级最高。
// 默认的线程优先级是 0.5 
Thread.current().threadPriority

线程的优先级一般不需要修改。线程的优先级不一定决定线程的执行循序。
(经典例子:优先级反转)
优先级高只能说明 cpu 在调度的时候回优先调度,并不意味着,优先级低的就不会调度。

多线程开发注意

  • 优先级只能说明 cpu 优先调度,并不意味着优先级低的不调度。(不要改优先级)
  • 不能相信一次执行的结果。
  • 不要去做不同线程的比较。

葵花宝典:
多线程开发一定要简单。(越复杂越不可控)

4、线程间通讯 (重点中的重点)

在子线程进行耗时操作,在子线程完成后,根据子线程的执行结果刷新UI界面。
(有的时候,不在主线程更新 UI 也不会有问题。 但是一定要在主线程更新 UI)

/**
    #selector(refresUI) : 调用的方法
    with: nil  要传递到主线程的参数。我这里传的是 nil 表示不传参数。
    waitUntilDone : true  等待主线程方法执行完毕
                              false  不等待主线程方法执行完毕
    (说白了就是线程的串行和并行的问题, 为 true 的是线程串行, false 为并行  )
*/
self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: true)

第一种创建线程的方式

print("befor -\(Thread.current())")
// 1. thread 对象, 在子线程中执行耗时操作
let thread = Thread(target: self, selector: #selector(longOperation), object: nil)
        
// 2. 启动线程
thread.start()

print("after -\(Thread.current())")


// 耗时操作
func longOperation(sender: AnyObject){
   
    // 模拟的耗时操作
    print("longOperation -\(Thread.current())")

    // object 参数对象可以用来进行线程之间传值
    self.performSelector(onMainThread: #selector(refresUI), with: nil, waitUntilDone: false)
}


// 刷新界面
func refresUI(){
    print("refresUI -\(Thread.current())")
}

// 打印结果
befor -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}
after -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}
longOperation -<NSThread: 0x7fb0b2f06610>{number = 3, name = (null)}
refresUI -<NSThread: 0x7fb0b2c059b0>{number = 1, name = main}

耗时操作是在子线程执行的,刷新 ui 是在主线程执行的

分离线程的方式
进行了线程之间的传值


print("befor -\(Thread.current())")

Thread.detachNewThreadSelector(#selector(longOperation), toTarget: self, with: "detachNewThread")

print("after -\(Thread.current())")

// 耗时操作
func longOperation(sender: AnyObject){

    // 模拟的耗时操作
    print("longOperation -\(Thread.current()) + 线程之间的传递的值:\(sender)")


    self.performSelector(onMainThread: #selector(refresUI), with: sender, waitUntilDone: false)
}


// 刷新界面
func refresUI(sender: AnyObject){
    print("refresUI -\(Thread.current()) + 线程之间的传递的值:\(sender)")
}

// 打印的结果
befor -<NSThread: 0x7ff3e2d06550>{number = 1, name = main}
after -<NSThread: 0x7ff3e2d06550>{number = 1, name = main}
longOperation -<NSThread: 0x7ff3e2d1e440>{number = 3, name = (null)} + 线程之间的传递的值:detachNewThread
refresUI -<NSThread: 0x7ff3e2d06550>{number = 1, name = main} + 线程之间的传递的值:detachNewThread

用 NSObject 执行后台线程
(我个人比较喜欢这种方式)

print("befor -\(Thread.current())")

self.performSelector(inBackground: #selector(longOperation), with: "inBackgroundThread")

print("after -\(Thread.current())")


// 耗时操作
func longOperation(sender: AnyObject){

    // 模拟的耗时操作
    print("longOperation -\(Thread.current()) + 线程之间的传递的值:\(sender)")


    self.performSelector(onMainThread: #selector(refresUI), with: sender, waitUntilDone: false)
}


// 刷新界面
func refresUI(sender: AnyObject){
    print("refresUI -\(Thread.current()) + 线程之间的传递的值:\(sender)")
}

打印结果
befor -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main}
after -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main}
longOperation -<NSThread: 0x7f9c6d415d90>{number = 3, name = (null)} + 线程之间的传递的值:inBackgroundThread
refresUI -<NSThread: 0x7f9c6ad078b0>{number = 1, name = main} + 线程之间的传递的值:inBackgroundThread

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

推荐阅读更多精彩内容

  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎样m阅读 1,263评论 0 1
  • 下面是我自己收集整理的Java线程相关的面试题,可以用它来好好准备面试。 参考文档:-《Java核心技术 卷一》-...
    阿呆变Geek阅读 14,735评论 14 507
  • Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么? 1...
    AlanGe阅读 1,714评论 0 17
  • 一、多线程基础 基本概念 进程进程是指在系统中正在运行的一个应用程序每个进程之间是独立的,每个进程均运行在其专用且...
    AlanGe阅读 542评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139