iOS开发学习之多线程

来源:互联网 发布:shake it off下载 编辑:程序博客网 时间:2024/04/30 01:19


  • 多线程
1进程指在系统运行的程序  如:QQ Xcode两个正在运行的进程
2每一个进程至少有一条线程,进程的所有的任务都在线程中执行,线程是进程的基本执行单元。
3线程的串行,一条线程只能执行一个任务,可以认为线程是进程中的执行路径
4原理:进程好比车间,线程好比车间工人。同一时间内,CPU只处理一条线程,多线程并发执行,其实是CPU快速地在多线程之间调度和切换。
5过度使用开启多个线程会造成不好的后果 1.CPU会累死 2.每条线程被调度执行的频率会降低 3.占用一定的内存空间 4.CPU调度线程的开销就越大
6实现方案:Pthread/NSThread/GCD/NSOperation
  • 主线程
作用:1.显示UI界面  2.处理UI事件(点击,滚动,拖拉)
注意:不要将耗时的操作放到主线程中,不然会出现“卡”的不良用户体验。解决措施:将耗时操作放在子线程(非主线程/后台线程),这样用户点击就能做出反应,能同时处理耗时操作和UI控件事件。  
  • 多线程的多种创建方式
1.Pthread创建子线程 不过不常用。

/** *  1.pthread创建子线程 */-(void)pthread{    NSThread *currentThread = [NSThread currentThread];    NSLog(@"%@", currentThread);    pthread_t threadId;    pthread_create(&threadId, NULL, run, NULL);}void *run(void *data){    NSThread *currentTread = [NSThread currentThread];    NSLog(@" %@",currentTread);    return NULL;}


2.NSThread可通过initWithTarget:Selector:Object创建一条子线程,并用start方法开启线程。


/** *   2.用NSThread创建子线程并start开启线程 */-(void)NSThread{    // 创建子线程    NSThread *currentThread1 = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"JHA"];    currentThread1.name = @"线程A";        // 开启线程    [currentThread1 start];        // 创建子线程    NSThread *currentThread2 = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"JHB"];    currentThread2.name = @"线程B";        // 开启线程    [currentThread2 start];    }


3.隐式创建子线程并启动

/** *  隐式创建子线程自动启动线程 (在后台进行) */-(void)performSelectorInBackground{    // 在后台执行 == 在子线程执行    [self performSelectorInBackground:@selector(run:) withObject:@"performSlectorInback"];}



4.创建线程后自动启动线程

/** *  4.断开分成两条新的线程 */-(void)detachNewThread{    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"detachNewThread.A"];    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"detachNewThread.B"];}-(void)run:(NSString *)param{    for (int i=0; i<100; i++) {        NSThread *current = [NSThread currentThread];        NSLog(@" %@ --run -- %@",current,param);    }}

第3种方式和第4种方式的缺点:无法对线程进行更详细的设置

  • 多线程的安全隐患
解决措施:加锁
枷锁格式:@synchronized(锁对象){}  注意:只能是同一把锁
加锁前提:多条线程抢夺同一块资源
线程同步:表示多条线程按顺序地执行,其实本质就是在线程当中加锁
我们在开发项目的时候,一些特殊属性 它们也被加了锁。
atomic:原子属性.会为setter方法加锁 
nonatomic:非原子属性,不会为setter方法加锁
atomic:线程安全 需要消耗大量的资源
nonatomic:非线程安全,适用内存小的移动设备
先下代码说明多线程抢夺资源后引发的安全性问题。

////  JHViewController.m//  线程安全////  Created by cjj on 15-10-28.//  Copyright (c) 2015年 jh.chen. All rights reserved.//#import "JHViewController.h"@interface JHViewController ()@property (nonatomic, strong) NSThread *thread1;@property (nonatomic, strong) NSThread *thread2;@property (nonatomic, strong) NSThread *thread3;@property (nonatomic, assign) int leftTicketsCount;@property (nonatomic, strong) NSLock *lock;@end@implementation JHViewController- (void)viewDidLoad{    [super viewDidLoad];    self.leftTicketsCount = 100;        self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.thread1.name = @"售票员A";        self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.thread2.name = @"售票员B";        self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];    self.thread3.name = @"售票员C";    self.lock = [[NSLock alloc] init];}-(void)sale{    while (1) {//        @synchronized (self.lock){ // 加锁            int count = self.leftTicketsCount;                        if (count > 0) {                [NSThread sleepForTimeInterval:0.02];                self.leftTicketsCount = count - 1;                NSThread *current = [NSThread currentThread];                NSLog(@"%@ 卖了一张 还剩下 %d张", current.name,self.leftTicketsCount);                            } else {                [NSThread exit];            }//        } // 解锁    }}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    [self.thread1 start];    [self.thread2 start];    [self.thread3 start];}@end


通过运行打印 我们知道有重复的数值。这就是抢夺同一资源的问题。至于解决方法就是往其加锁。打开上面代码注释边即可。
  • 线程间通信
定义:线程往往不是孤立存在,多个线程之间需要经常进行通信。
例如:下面子线程和主线程之间的切换。

#import "JHViewController.h"@interface JHViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation JHViewController- (void)viewDidLoad{    [super viewDidLoad];}-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    // 下载图片 (开启子线程)    [self performSelectorInBackground:@selector(download) withObject:nil];}/** *  下载图片 : 子线程 */-(void)download{    // 根据URL下载图片    NSURL *url = [NSURL URLWithString:@"www.baidu.com"];    NSData *data = [NSData dataWithContentsOfURL:url];    UIImage *image = [UIImage imageWithData:data];        // 回到主线程    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];//    [self.imageView performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];}/** * 显示图片: 主线程 */-(void)settingImage:(UIImage *)image;{    self.imageView.image = image;}@end




  • GCD “牛逼的中枢调度器” 
优势:
苹果公司为多核的并行运算提出的解决方法
GCD会自动利用更多的CPU内核
GCD会自动管理线程的生命周期
程序员只告诉GCD想要执行什么任务,无需写线程管理代码
GCD的使用步骤:1.定制任务 2.将任务添加到队列中(fifo 先进先出)

GCD中有2个用来执行任务的函数:
1、用同步的方式执行任务 :dispatch_sync;
2、用异步的方式执行任务:dispatch_async;
延时执行:
1、调用NSObject的方法[self performSelector:withObject:afterDelay:];
2、使用GCD函数  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    });
一次性代码:    
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
 });
常见术语解释 同步.异步.并发.串行:
^ 同步:在当前线程中执行任务,不具备开启新线程能力
^异步:在新的线程中执行任务,具备开启新线程能力
^并发:多个任务同时执行
^串行:一个任务执行完后,再执行下一个任务
同步函数和异步函数:
同步函数
1.并发队列:不会开线程
2.串行队列:不会开线程
异步函数:
1.并发队列:能开N条线程
2.串行队列:开启一条线程

如果有什么建议 请联系虾米:
QQ:584837022
微信:foreverlovewillgoon

1 0
原创粉丝点击