多线程(2)——NSThread

iOS中实现多线程的四种方案

  • pthread
  • NSThread
  • GCD
  • NSOpreation

Pthread:这种纯c语言的就别用了吧,还要自己管理线程的生命周期,果断不用
NSThread:这个虽然自己管理线程的生命周期,但这是面向对象的,OC语言,不常用到但要会用
GCD:这个很重要、很重要、很重要 自动管理线程的生命周期 使用率非常非常频繁
NSOpreation:这个也很重要,必须掌握,没什么好说的,也是自动管理线程的生命周期,使用率也非常高

简单了解下Pthread

只要create一次就会创建一个新的线程
系统会自动在子线程中调用传入的函数

  /*
第一个参数: 线程的代号(当做就是线程)
第二个参数: 线程的属性
第三个参数: 指向函数的指针, 就是将来线程需要执行的方法
第四个参数: 给第三个参数的指向函数的指针 传递的参数
一般情况下C语言中的类型都是以 _t或者Ref结尾
  */
pthread_t threadId;
// 只要create一次就会创建一个新的线程
pthread_create(&threadId , NULL, &demo, "hq");

关于NSThread

  • NSThread对比后面两种是相对轻量级的,更直观地控制线程对象
  • 但需要自己管理线程的生命周期、同步、加锁问题,在性能上会有一定的消耗
  • 注意:一个NSThread对象就代表一条线程

创建方法

** 第一种方法 ** (手动开启线程)

// 线程一启动,就会在线程thread中执行self的run方法

// 1.创建线程
NSThread *thread = [[NSThread alloc] initWithTarget:selfselector:@selector(run) object:nil];

// 2.设置线程的优先级(0.0 - 1.0,1.0最高级)  
thread.threadPriority = 1; 

// 3.启动线程
[thread start];

** 第二种方法 ** (自动开启线程)

// detachNewThreadSelector: 不用手动调用start方法, 系统会自动启动 没有返回值, 不能对线程进行更多的设置

[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

** 第三种方法 ** (隐式创建并启动线程)

// 系统就会自动创建一个子线程, 并且在子线程中自动执行self的@selector方法

[self performSelectorInBackground:@selector(run) withObject:nil];

NSThread用法

  • 主线程相关用法
 + (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
+ (BOOL)isMainThread; // 是否为主线程
NSThread *main = [NSThread mainThread];
  • 获得当前线程
NSThread *current = [NSThread currentThread];
  • 获取线程的名字

    - (void)setName:(NSString *)name;
    - (NSString *)name;
    

线程的状态

  • 创建出来 -> 新建状态
  • 调用start -> 准备就绪
  • 被CPU调用 -> 运行
  • sleep -> 阻塞
  • 执行完毕, 或者被强制关闭 -> 死亡
启动线程
- (void)start; 
// 进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态

阻塞(暂停)线程
// sleep方法是一个类方法, 所以说明在哪个线程中调用, 就会给哪个线程设置暂时
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)time;

// 暂停1s  
[NSThread sleepForTimeInterval:1]; 
[NSThread sleepUntilDate:[NSDate dateWithTimeInterval:1 sinceDate:[NSDate date]]];
强制停止线程
// 进入死亡状态
+ (void)exit;
注意:一旦线程停止(死亡)了,就不能再次开启任务

多线程的安全隐患及解决措施

  • 资源共享
    • 一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象、同一个变量、同一个文件等
    • 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题
  • 解决措施
    • 互斥锁
    • 互斥锁的使用前提:多条线程抢夺同一块资源
    • 注意:锁定1份代码只用1把锁,用多把锁是无效的
  • 使用格式
// (锁对象self)
@synchronized
{ 
    // 需要锁定的代码      
}
        /*
         只要被@synchronized的{}包裹起来的代码, 同一时刻就只能被一个线程执行
         注意:
         1. 只要枷锁就会消耗性能
         2. 加锁必须传递一个对象, 作为锁
         3. 如果想真正的锁住代码, 那么多个线程必须使用同一把锁才行
         4. 加锁的时候尽量缩小范围, 因为范围越大性能就越低
         */
  • 互斥锁的优缺点

    • 优点:能有效防止因多线程抢夺资源造成的数据安全问题
    • 缺点:需要消耗大量的CPU资源
  • 线程同步

    • 线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务)
      互斥锁,就是使用了线程同步技术

原子和非原子属性

  • OC在定义属性时有nonatomic和atomic两种选择
    • atomic:原子属性,为setter方法加锁(默认就是atomic)
    • nonatomic:非原子属性,不会为setter方法加锁
  • 原子和非原子属性的选择
    • atomic:线程安全,需要消耗大量的资源
    • nonatomic:非线程安全,适合内存小的移动设备
  • iOS开发的建议
    • 所有属性都声明为nonatomic
    • 尽量避免多线程抢夺同一块资源
    • 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

注意点: atomic系统自动给我们添加的锁不是互斥锁/ 自旋锁

  • 自旋锁和互斥锁对比
    • 相同点:都能够保证多线程在同一时候, 只能有一个线程操作锁定的代码
    • 不同点
      • 如果是互斥锁, 假如现在被锁住了, 那么后面来得线程就会进入”休眠”状态, 直到解锁之后, 又会唤醒线程继续执行
      • 如果是自旋锁, 假如现在被锁住了, 那么后面来得线程不会进入休眠状态, 会一直傻傻的等待, 直到解锁之后立刻执行
      • 自旋锁更适合做一些较短的操作

线程间的通信

  • 什么叫做线程间通信

    • 在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信
    • 比如在主线程添加imageView,在子线程中下载图片,然后又回到主线程中显示图片
    • 注意点: 更新UI一定要在主线程中更新
  • 线程间通信的体现

    • 1个线程传递数据给另1个线程
    • 在1个线程中执行完特定任务后,转到另1个线程继续执行任务
  • 在当前线程

[self performSelector:@selector(run) withObject:nil]; 
  • 在主线程

    [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
    
  • 在指定线程

[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];  

// waitUntilDone的含义: 如果传入的是YES: 那么会等到主线程中的方法执行完毕, 才会继续执行下面其他行的代码 如果传入的是NO: 那么不用等到主线程中的方法执行完毕, 就可以继续执行下面其它行的代码

线程间的通信最常见的就是在子线程中做耗时操作,然后回到主线程刷新UI

关于NSThread的总结

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

推荐阅读更多精彩内容

  • 一、多线程基础 基本概念 进程进程是指在系统中正在运行的一个应用程序每个进程之间是独立的,每个进程均运行在其专用且...
    AlanGe阅读 546评论 0 0
  • 多线程基本概念 单核CPU,同一时间cpu只能处理1个线程,只有1个线程在执行 。多线程同时执行:是CPU快速的在...
    WeiHing阅读 706评论 1 5
  • 线程概述 有些程序是一条直线,起点到终点;有些程序是一个圆,不断循环,直到将它切断一个运行着的程序就是一个进程或者...
    褪而未变阅读 298评论 0 0
  • 希望有一天你难过了,会第一个想起我的名字。
    436522a73fa0阅读 220评论 0 1
  • 一、初相识 我和晓玥认识的时候是在高一军训的时候。我记得那时候是夏天吧,大家都穿着军训服在训练场上跑步。因为我自己...
    我是影子啊阅读 566评论 5 5