码迷,mamicode.com
首页 > 移动开发 > 详细

iOS之多线程

时间:2015-09-16 21:28:51      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

概述

程序:

一个可以运行的文件(我们写的代码)

进程 

是程序执行的一个操作实体 

在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ、Xcode,系统就会分别启动2个进程

 通过“活动监视器”可以查看Mac系统中所开启的进程

线程:(Thread)线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行    

一个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程)

    比如使用酷狗播放音乐、使用迅雷下载电影,都需要在线程中执行

线程的串行

    1个线程中任务的执行是串行的

    如果要在1个线程中执行多个任务,那么只能一个一个地按顺序执行这些任务

    也就是说,在同一时间内,1个线程只能执行1个任务

    比如在1个线程中下载3个文件(分别是文件A、文件B、文件C)

这篇文章中,我不会说多线程是什么、线程和进程的区别、多线程有什么用,当然我也不会说什么是串行、什么是并行等问题,这些我们应该都知道的。

多线程

同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

如果线程非常多,会出现什么效果?

cpu在很多的线程之间切换,cpu会被累死,消耗了太多的cpu资源,单次执行线程的间隔越来越长,频次越来越低,任务执行效率也就越低。

那么多线程有什么优点和缺点呢?

1.多线程的优点:1)能适当地提高程序的执行效率。2)能适当提高资源利用率。(比如cpu,内存等)

2.多线程的缺点:1)开启线程需要占用一定的内存空间。默认情况下,主线程占用1M 子线程占用512KB 如果开启了大量的线程,会占用大量的内存空间 降低程序性能。2)线程越多,cpu在调度线程上的开销越大。3)线程设计更加复杂,比如线程之间的通信多线程的数据共享。

3.多线程在iOS开发中的应用

主线程:一个iOS程序运行之后,默认会开启一条线程,称之为 主线程或者UI线程。

主线程的主要作用:刷新界面,显示界面 处理UI事件。

主线程的使用注意点:不要把比较耗时间的操作放到主线程中。 耗时操作会卡住主线程,严重影响UI的流畅度。 

iOS线程模型

 pthread 底层的c线程库

 NSThread oc线程库

 NSOperationQueue 线程队列

 Blocks/GCD

主线程处理 工程1 耗时操作

点击事件
-(IBAction)threadDoWork:(id)sender
{
    int i = 0;
    while (i++ <10) {
        NSLog(@"%@",@"好吧 我开始工作了");
        [NSThread sleepForTimeInterval:1.0];
NSLog(@"%@",[NSThread currentThread]); } NSLog(
@"%@",@"完成了"); }
//再加一个
//耗时操作
-(IBAction)threadDoSleep:(id)sender
{
    int i = 0;
    while (i++ <10) {
        //线程休眠
        //这里并没有开辟新线程,那么休眠的是主线程。
        //哪个线程执行sleep休眠的是哪个
        //响应UI事件的是在主线程
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"%@",@"我睡着了 不要烦我");
    }
    NSLog(@"%@",@"睡醒了");
}

添加两个按钮,btn1事件触发工作,btn2事件触发睡觉。

当我点击相应的按钮之后,会有相应的输出。总结:

1)主线程相应我们操作。

2)主线程处理任务,都是按照自然顺序处理,谁先来处理谁,在一件事没有处理完成之前,它不会去处理其他的事情。

3) currentThread是当前线程,获得当前逻辑代码是在那个线程中。

4)主线程的number =1 name=main

那么问题来了,既然响应在主线程中进行处理,那么如果耗时操作的数据量和处理特别复杂时 当前的界面会变的很卡很卡。该怎么解决这个问题呢?答案是多线程。

主线程上执行的操作最好都是及时响应的,不能让用户觉得我们的程序卡死,那样使得用户体验很不好。

那么这样的耗时操作我们应该放在哪里呢?答案是子线程。1)一定不要在子线程中做这件事。2)开启一条新的线程来完成耗时操作。

 

接下来讨论子线程。

 1.pthread 用c方法创建子线程。主要方法:

    pthread_t cThread;

    int b = pthread_create(&cThread, NULL, working, NULL);

限制性:只能开线程。不能控制。

2.NSThread

官方定义: 

NSThread定义
 @interface NSThread : NSObject  {
 @private
 id _private;
 uint8_t _bytes[44];
 }
 + (NSThread *)currentThread;//当前的线程 {number name}
 
 + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;//类方法 将操作直接添加到线程中运行。
 
 
 + (BOOL)isMultiThreaded;//是否是多线程工作模式?
 
 @property (readonly, retain) NSMutableDictionary *threadDictionary;
 
 + (void)sleepUntilDate:(NSDate *)date;//休眠直到date
 + (void)sleepForTimeInterval:(NSTimeInterval)ti;//休眠ti秒
 
 + (void)exit;//退出。
 
 + (double)threadPriority;//优先级
 + (BOOL)setThreadPriority:(double)p;//方法设置优先级
 
 @property double threadPriority NS_AVAILABLE(10_6, 4_0); // To be deprecated; use qualityOfService below
 
 @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); // read-only after the thread is started
 
 + (NSArray *)callStackReturnAddresses NS_AVAILABLE(10_5, 2_0);
 + (NSArray *)callStackSymbols NS_AVAILABLE(10_6, 4_0);
 
 @property (copy) NSString *name NS_AVAILABLE(10_5, 2_0);//属性:线程名称
 
 @property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);
 
 @property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
 + (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); //判断当前线程是否是主线程
 + (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);获取主线程
 
 - (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument NS_AVAILABLE(10_5, 2_0);//初始化的同时添加操作,并执行。
 
 @property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);
 @property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);//判断是否完成任务?
 @property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);//
 
 - (void)cancel NS_AVAILABLE(10_5, 2_0);
 
 - (void)start NS_AVAILABLE(10_5, 2_0);
 
 - (void)main NS_AVAILABLE(10_5, 2_0);    // thread body method
 
 @end
 
 FOUNDATION_EXPORT NSString * const NSWillBecomeMultiThreadedNotification;
 FOUNDATION_EXPORT NSString * const NSDidBecomeSingleThreadedNotification;
 FOUNDATION_EXPORT NSString * const NSThreadWillExitNotification;
 
 @interface NSObject (NSThreadPerformAdditions)
 
 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
 - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
    // equivalent to the first method with kCFRunLoopCommonModes
 
 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
 - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
    // equivalent to the first method with kCFRunLoopCommonModes
 - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);
 
 @end

用NSThread创建单个线程

技术分享
#pragma mark -创建线程 单个
-(void)createThread
{
    // 类方法
    /*
     [NSThread detachNewThreadSelector:@selector(doWorking) toTarget:self withObject:nil];
     */
    //对象方法
    /* NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(doToilet) object:nil];
    */
    
    //NSThread 是cocoa(macOS,iOS)中一个轻量级的线程对象。
    NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(doToilet) object:nil];
    thread.name = @"我的线程";
    //使用alloc创建的线程 一定要调用start方法,才能运行。
    [thread start];
    
    //类方法
    [NSThread detachNewThreadSelector:@selector(doWorking) toTarget:self withObject:nil];
    //类方法退出,以下代码不会执行。
    //[NSThread exit];
    NSLog(@"%@",@"-s-s-s-");
}
View Code
执行方法:
技术分享
#pragma mark -任务
-(void)doWorking
{
    int i = 0;
    while (i++ <10) {
        //获取当前线程
        NSThread *thread = [NSThread currentThread];
        NSLog(@"%@学习了%d秒",thread.name,i);
        [NSThread sleepForTimeInterval:1.0];
    }
    NSLog(@"%@",@"完成了");
}
View 

让线程做多件事情

-(IBAction)doWorking:(id)sender{
//    [self doWorking];
    [self createThreads:0];
}
-(IBAction)doWCing:(id)sender{
//    [self doWCing];
//    [self createThread];
    [self createThreads:1];
}点击触发
-(void)createThreads:(int)n{

    switch (n) {
        case 0:
            //创建多个工作的线程
            for (NSInteger i = 0; i<3; i++) {
                //开辟工作线程
                NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(doWorking) object:nil];
                //可以给线程取个名字,加以区分
                [thread setName:[NSString stringWithFormat:@"工作线程%ld号",i+1]];
                
                //设置线程的优先级
                thread.threadPriority = i+1;
                //作用并不明显,并不能控制线程的顺序
                
                [thread start];
            }
            break;
        case 1:
            //创建多个工作的线程
            for (NSInteger i = 0; i<3; i++) {
                //开辟工作线程
                NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(doWCing) object:nil];
                //可以给线程取个名字,加以区分
                [thread setName:[NSString stringWithFormat:@"工作线程%ld号",i+1]];
                
                //设置线程的优先级
                thread.threadPriority = i+1;
                //作用并不明显,并不能控制线程的顺序
                
                [thread start];
            }
            break;
        default:
            break;
    }
}

对资源加锁

-(void)doWorking{
    int i = 0;
    while (i++<10) {
        //获取当前的线程
        NSThread *thread = [NSThread currentThread];
        NSLog(@"%@学",thread.name,i);
        [NSThread sleepForTimeInterval:1.0];
    }
    NSLog(@"完成");
}
/**
 *  
 */
-(void)doWCing{
    if(_threadLock == nil){
        _threadLock = [[NSLock alloc]init];
    }
    //上锁
    [_threadLock lock];
    
    @synchronized(self){
    
    int i = 0;
    while (i++<10) {
        //获取当前的线程
        NSThread *thread = [NSThread currentThread];
        NSLog(@"%@%d秒",thread.name,i);
        [NSThread sleepForTimeInterval:1.0];
    }
    NSLog(@"完成");
    }
    //解锁
    [_threadLock unlock];
}

然而 NSThread难于人为地去控制创建子线程的数量。子线程创建过多,会严重地影响程序的性能,因为每一个线程都会占用一定cpu的资源,导致cpu很忙碌。

那么怎么解决这个问题?用GCD。

下一章讨论GCD的内容。

iOS之多线程

标签:

原文地址:http://www.cnblogs.com/mosuyanxue/p/4811721.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!