多线程入门

相关知识点引入

多线程优秀博客:(关于iOS多线程,你看我就够了)https://www.jianshu.com/p/0b0d9b1f1f19

1.进程和线程

进程:指系统上正在运行的程序;例如:我们打开QQ是一个进程,打开Xcode也是一个进程
线程:指程序在执行过程中,能够执行程序代码的一个执行单元(也就是线程是运行在程序中)
二者关系:一个进程可以有多个线程;线程是进程的执行单元;
各个线程之间共享程序的内存空间,但是各个线程又拥有自己独立的内存空间。1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程;一个进程(程序)的所有任务都在线程中执行;注意:1个线程中任务的执行是串行的)


多线程入门_第1张图片
多线程入门_第2张图片
屏幕快照 2016-01-29 上午10.09.13.png

2.串行和并行

串行:一个线程执行多个任务,采取排队方式执行;
并行:多个线程分担多个任务,不同任务同时执行(食堂窗口打饭)

3.同步和异步(主要考虑阻塞问题)

同步:当前面一个任务未完成,后面的任务就会被阻塞;
异步:不同的任务在不同的线程中执行,当子线程发生阻塞,主线程和其他线程不会受到影响(食堂窗口打饭)
注意:异步强调解决阻塞问题,可以开辟新的线程执行任务;并发指子线程之间的关系,多个任务同时执行

4.多线程:
多线程概念:1个进程中可以开启多条线程,多条线程可以并行(同时)执行不同的任务
多线程原理
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
为什么使用多线程

可以减少程序的响应时间、简化程序结构、内存开销更小、能适当提高程序的执行效率、能适当提高资源利用率(CPU、内存利用率)等等

多线程缺点

1.对其他程序不友好(例抢红包)
2.可能占用了更多的CPU资源。当然,也不是线程越多,程序的性能就越好,因为线程之间的调度和切换也会浪费CPU时间。

思考:如果线程非常非常多,会发生什么情况?

多条线程会再CPU来回切换,会销毁大量的CPU资源
每条线程被调度执行的频度会变小,线程的执行效率会降低伴随着

5.主线程

1).概念:一个iOS程序运行后,默认会开启1条线程,称为“主线程”或“UI线程”
2). 作用: 显示\刷新UI界面; 处理UI事件
3).使用主线程注意:

  • 别将比较耗时的操作放到主线程中(一般都在子线程(后台线程、非主线程)处理耗时操作后回到主线程中刷新UI界面);
  • 耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验

五种方法

1.GCD(Grand Central Dispatch)

概念:是实现多线程的一种方法;是一套底层API,GCD的API很大程度上基于block,当配合block使用时,GCD非常简单易用且能发挥其最大能力。
队列有三种:用户队列、全局队列、主队列

---使用经典(常用)形式---
1.先全局的并发队列,异步(供整个应用使用;执行耗时的异步操作 )

dispatch_async(dispatch_get_global_queue(0,0),^{
   
  // 第一个0表示默认的全局队列的优先级,可记为固定;第二个是保留   
              的参数,没什么用,直接写0
      代码...

});
�

2.回到主队列(刷新界面 )

dispatch_async(dispatch_get_main_queue(),^{

代码...

});

Demo

//插座变量
@property (weak, nonatomic) IBOutlet UIImageView *baiduImageView;

//开始触摸事件
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    //为避免循环引用;采取弱引用方式(遇到block大多可采用此方法)
    __weak typeof(self)weakSelf=self;

    //1.先创建一个全局并发队列
    dispatch_queue_t queue=dispatch_get_global_queue(0, 0);
    
    //2.调用异步函数
    dispatch_async(queue, ^{
        
        NSString *strUrl=[NSString stringWithFormat:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png"];
        
        NSURL *url=[NSURL URLWithString:strUrl];
        
        NSData *data=[NSData dataWithContentsOfURL:url];
        
        UIImage *image=[UIImage imageWithData:data];
        
        
        //3.主队列刷新界面
        dispatch_sync(dispatch_get_main_queue(), ^{
            
            weakSelf.baiduImageView.image=image;
            
        });
        
    });
}

2.NSOperation方法

创建一个操作对象,然后将其扔到队列中去,再最后回到主线程刷新

创建一个操作对象(待会要将该队列放到一个队列中去执行)
NSOperation *op=[NSBlockOperation blockOperationWithBlock:^{
[self foo:sender];
}];
创建一个并发对列
NSOperationQueue *queue=[NSOperationQueue alloc]init];
//设置最大并发数量
queue.maxConcureentOperationCount=5;
//向对列中添加一个操作
[queue addOperation:op];

1.创建一个操作对象
NSOperation *op=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(bar:)object:button];
2.向主队列中添加操作对象(操作放到主线程中执行)
[[NSOperationQueue mainQueue]addOperation:op];

3.pThreads - POSIX

是C语言写的函数,可以实现多线程;但使用非常麻烦,要调非常多的函数...

4.NSThread方法

5.NSObject扩展(补丁包)

选择器方法

//开辟新线程执行耗时操作(相当于放在后台新线程中执行)以免阻塞为主线程
performSelectorInBackground:withObject:
//主线程刷新
performSelectorOnMainThread: withObject: waitUntilDone:

NSThread(有2种方式执行)

一.实现方法
//方法1:
[NSThread detachNewThreadSelector:@selector(foo:) toTarget:self withObject:sender];
//方法2:
 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(foo:) object:sender];
    // 启动线程(执行foo回调方法)
  [thread start];

 // sleep(1);
  // 提示: 如果线程已经开始执行则无法取消
    // [thread cancel];
具体看课程代码

二.考虑开辟多条线程竞争同一资源(或多个资源,这考虑同一的情况)
//可在AppDelegate.m中写
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 创建一个可变字符串作为多个线程共同竞争的一个资源
    NSMutableString *mStr = [NSMutableString stringWithCapacity:50000];
    // 创建5个线程操作同一个资源
    for (int i = 1; i <= 5; i++) {
        [NSThread detachNewThreadSelector:@selector(foo:) toTarget:self withObject:mStr];
    }
    return YES;
}
- (void) foo:(NSMutableString *) mStr {
    for (int i = 0 ; i < 10000; i++) {
        // 提示: 如果多个线程竞争同一个资源通常需要进行同步保护
        // 同步: 只让一个线程获得资源使用完毕后下一个线程才能获得(排队方式)
        // 该资源其他线程仍然等待使用资源的线程释放资源
        @synchronized (mStr) {
            [mStr appendString:@"a"];
        }
    }
}

NSOperation

使用NSOperation的子类NSInvocationOperation和NSBlockOperation

//两个按钮那个例子(讲NSBlockOperation)
- (IBAction)onbuttonClicked:(UIButton *)sender {
    sender.enabled=NO;
    [sender setTitle:@"执行中" forState:0];
   //1创建任务(以block形式)
    NSOperation *op=[NSBlockOperation blockOperationWithBlock:^{
        sleep(10);
        NSLog(@"任务1完成");
        
        //3.再创建一个队列,然后放在主队列中(就会在主线程中执行),来刷新界面
        NSOperation *op2=[NSBlockOperation blockOperationWithBlock:^{
            [sender setTitle:@"button1" forState:0];
        }];
        [[NSOperationQueue mainQueue]addOperation:op2];//刷新界面
        
    }];
    //2并发队列(同时执行放在里面的任务)
    NSOperationQueue *queue=[[NSOperationQueue alloc]init];
    [queue addOperation:op];//相队列中添加一个任务(操作)

}

只执行一次处理
static dispatch_once_t token;
dispatch_once(&token, ^ {});

总结

多线程入门_第3张图片

代码只被执行一次:

(利用这种方式,可以简单的创建一个单例对象)
方法dispatch_once(&,^(void){});

static dispatch_once_t onceToken;
 
     dispatch_once(&onceToken,^{
 
       NSLog(@"代码块只执行了一次");
});

拓展

1.runloop与线程有什么关系?

总的说来,Run loop,正如其名,loop表示某种循环,和run放在一起就表示一直在运行着的循环。实际上,run loop和线程是紧密相连的,可以这样说run loop是为了线程而生,没有线程,它就没有存在的必要。Run loops是线程的基础架构部分, Cocoa 和 CoreFundation 都提供了 run loop 对象方便配置和管理线程的 run loop (以下都以 Cocoa 为例)。每个线程,包括程序的主线程( main thread )都有与之相应的 run loop 对象。

runloop 和线程的关系

1.主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数

int main(int argc, char * argv[]) {
@autoreleasepool {
 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。
2.对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。
3.在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。

NSRunLoop *runloop = [NSRunLoop currentRunLoop];

2.runloop的mode作用是什么?

model 主要是用来指定事件在运行循环中的优先级的,分为:
1.NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
2.UITrackingRunLoopMode:ScrollView滑动时
3.UIInitializationRunLoopMode:启动时
4.NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

苹果公开提供的 Mode 有两个:
NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
NSRunLoopCommonModes(kCFRunLoopCommonModes)

有关Runloop的优秀博客:http://www.jianshu.com/p/cb2a1f25b646

你可能感兴趣的:(多线程入门)