服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
 热线电话: #
当前位置: 主页 > 开发教程 > ios开发教程 >

iOS四种多线程技术方案

时间:2016-02-16 00:53来源:未知 作者:最模板 点击:
iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param){ for (NSInteger i = 0; i 1000; i++) { NSLog(@---buttonclick---%zd---%@, i, [NSThread currentThread]); } return NULL;}@implementat

iOS 多线程的四种技术方案


image

pthread 实现多线程操作

代码实现:

void * run(void *param)
{
    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"---buttonclick---%zd---%@", i, [NSThread currentThread]);
    }

    return NULL;
}

@implementation ViewController

- (IBAction)clickButton:(id)sender {
    // 定义一个线程
    pthread_t thread;
    // 创建一个线程  (参1)pthread_t *restrict:创建线程的指针,(参2)const pthread_attr_t *restrict:线程属性  (参3)void *(*)(void *):线程执行的函数的指针,(参4)void *restrict:null
    pthread_create(&thread, NULL, run, NULL);
    // 何时回收线程不需要你考虑
    pthread_t thread2;
    pthread_create(&thread2, NULL, run, NULL);
}

NSThread实现多线程

一个 NSThread 对象就代表一条线程

创建线程的多种方式
  1. 第一种方式:先创建再启动线程
    // 创建线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    // 线程启动了,事情做完了才会死, 一个NSThread对象就代表一条线程
    [thread start];
  2. 第二种:直接创建并启动线程
    // 直接创建并启动线程
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"jack"];
  3. 第三种:
    // 直接创建并启动线程
    [self performSelectorInBackground:@selector(run:) withObject:@"jack"];
    // 使线程进入阻塞状态
    [NSThread sleepForTimeInterval:2.0];
#pragma mark - 执行run方法
- (void)run:(NSString *)param
{
    // 当前线程是否是主线程
    for (NSInteger i = 0; i < 100; i++) {
        NSLog(@"---%@---%zd---%d", [NSThread currentThread], i,  [NSThread isMainThread]);
    }
}

方法2和方法3的优点:快捷
方法1的优点:可以轻松拿到线程
线程间通信
线程间通信的体现
1个线程传递数据给另1个线程
在1个线程中执行完特定任务后,转到另1个线程继续执行任务
线程间通信的常用方法:小程序图片下载

-(UIImageView *)imageView
{
    if (!_imageView) {
        _imageView = [UIImageView new];
        _imageView.frame = CGRectMake(0, 0, 300, 300);
        _imageView.center = self.view.center;
        [self.view addSubview:_imageView];
    }
    return _imageView;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    //监听线程结束的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_threadexit:) name:NSThreadWillExitNotification object:nil];

    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //第一种方式:先创建再启动线程
    // 创建线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"booob"];

    // 线程启动了,事情做完了才会死, 一个NSThread对象就代表一条线程
    [thread start];

    //第二种:直接创建并启动线程
    // 直接创建并启动线程
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"wang"];


    //第三种:
    // 直接创建并启动线程
    [self performSelectorInBackground:@selector(run:) withObject:@"wang000"];
    // 使线程进入阻塞状态
    [NSThread sleepForTimeInterval:2.0];


    //例子
    // 获取图片的url
    NSURL *url = [NSURL URLWithString:@"https://pages.github.com/images/slideshow/yeoman.png"];
    // 另开1条线程 object用于数据的传递
    NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(downLoadWithURL:) object:url];
    thread3.name = @"downloadimage...";
    // 由于下面下载图片的耗时太长,应开启线程来完成
    [thread3 start];

}
#pragma mark - 执行run方法
- (void)run:(NSString *)param
{
    // 当前线程是否是主线程
    for (NSInteger i = 0; i < 10; i++) {
        NSLog(@"---%@---%zd---%d", [NSThread currentThread], i,  [NSThread isMainThread]);
    }

}

//线程直接的交互
// 下载图片
- (void)downLoadWithURL:(NSURL *)url
{
    NSLog(@"%s ,%s %@",__FILE__,__FUNCTION__, [NSThread currentThread]);
    // 下载图片
    NSData *data = [NSData dataWithContentsOfURL:url];
    // 生成图片
    UIImage *image = [UIImage imageWithData:data];
    // 返回主线程显示图片
    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}

//处理线程结束事件
-(void)handle_threadexit:(NSNotification *)notify
{
    NSThread  * thread = (NSThread *)notify.object;
    NSLog(@"+++++++++++++++ 线程 %@ 结束 ++++++++++++",thread.name);
}

TIPS: 拓展,线程结束的通知
以上下载图片方式使用线程已经过时了,开发中我们操作线程大多都使用 GCD 和 NSOperation 来实现多线程操作。

——————————————————————————————————————————

GCD 是如何实现多线程的

  • GCD 实现多线程
  • GCD 简介
  • GCD 全称是Grand Central Dispatch,可译为“超级厉害的中枢调度器”,GCD 是苹果公司为多核的并行运算提出的解决方案, GCD会自动利用更多的 CPU 内核(比如双核、四核)来开启线程执行任务,GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程),不需要我们程序员手动管理内存。

  • 任务和队列

  • 任务:在同步函数和异步函数中执行
  • 队列:用来存放任务(并发 串行)

images

GCD会自动将队列中的任务取出,放到对应的线程,任务的取出遵循FIFO,即先入先出队列,First Input First Output 的缩写。
先进入的任务先完成并结束,再执行后面的任务。
同步函数和异步函数,并发队列和串行队列
用同步的方式执行任务:在当前线程中可立即执行任务,不具备开启线程的能力
用异步的方式执行任务:在当前线程结束时执行任务,具备开启新的线程的能力

  • 并发队列:允许多个任务同时执行

  • 串行队列:一个任务执行完毕后,再执行下一个任务

创建并发/串行队列代码:

- (void)viewDidLoad {
    [super viewDidLoad];
      dispatch_queue_t queue = dispatch_get_main_queue();
    // 创建串行队列  serial 串行  concurrent并发
    queueSerial = dispatch_queue_create("searial.whenbar.com", DISPATCH_QUEUE_SERIAL);

    //创建并行队列
    // 参1:const char *label 队列名称
    // 参2:dispatch_queue_attr_t attr 队列类型
    queueConcurrent = dispatch_queue_create("concurrent.whenbar.com", DISPATCH_QUEUE_CONCURRENT);

}
//1 获得主队列
-(void)runqueueMain
{
    // 获取主队列  在主队列中的任务都会在主线程中执行。
    dispatch_queue_t queueMain = dispatch_get_main_queue();

}

//2. 创建串行队列
-(void)runqueueSerial
{

    // GCD同步函数串行队列(立即执行,当前线程)
    // 参1: dispatch_queue_t queue 队列
    // 参2: 任务
    dispatch_sync(queueSerial, ^{
        for (NSInteger i = 0; i < 10; i++) {
            NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
        }
    });


    // 异步函数串行队列 (另开线程,多个任务按顺序执行)
    dispatch_async(queueSerial, ^{
        dispatch_async(queueSerial, ^{
            for (NSInteger i = 0; i < 10; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
        dispatch_async(queueSerial, ^{
            for (NSInteger i = 0; i < 10; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
        dispatch_async(queueSerial, ^{
            for (NSInteger i = 0; i < 10; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
    });

}



//3. 创建并发队列
-(void)runqueueConcurrent
{

    // 同步函数并行队列(立即执行,当前线程)
    dispatch_sync(queueConcurrent, ^{
        for (NSInteger i = 0; i < 10; i++) {
            NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
        }
    });

    // 异步函数并行队列 (另开线程,多个任务一起执行)
    dispatch_async(queueConcurrent, ^{
        dispatch_async(queueConcurrent, ^{
            for (NSInteger i = 0; i < 5; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
        dispatch_async(queueConcurrent, ^{
            for (NSInteger i = 0; i < 6; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
        dispatch_async(queueConcurrent, ^{
            for (NSInteger i = 0; i < 7; i++) {
                NSLog(@"~~~%ld %@",i, [NSThread currentThread]);
            }
        });
    });
}

//4. 创建全局队列
-(void)runqueueGlobal
{
    // 获取全局队列 全局队列是并发队列
    // 参1:队列的优先级
    // 参2:0(以后可能用到的参数)//#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高\
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)\
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低\
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
    dispatch_queue_t queueGlobal = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

}

// 主队列:(任何一个任务只要在主队列中,都会加入到主线程的队列中执行)

TIPS: 注意
使用sync函数(同步函数)往当前串行队列中添加任务,会卡住当前的串行队列
解释:使用同步函数添加任务 A 到串行队列,说明要在当前串行队列立即执行任务 A ,任务 A 执行完后,才会执行任务 A 后面的代码。但当前队列是串行队列,也就是说任务 A 必须等到当前串行队列中正在执行的任务 B 完成之后才能执行,因此又必须先执行任务 A 中立即执行任务,又要必须等到任务 B 执行完以后才能执行下一个任务,所以就会卡死。你等我,我等你,谁也无法执行。

GCD实现线程通信

小项目:下载图片

代码如下:

// 获取图片的url
NSURL *url = [NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"];

// 开启线程下载图片
dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];

    // 下载完成后返回主线程显示图片
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = image;
    });
});

————————————————————————————————————————

GCD其他常用函数


image
//----------------- 队列组 -----------------------------
//队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。下面是使用方法,这是一个很实用的功能。
-(void)rungroup
{
    //1.创建队列组
    dispatch_group_t group=dispatch_group_create();
    //2.创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    //3.多次使用队列组的方法执行任务, 只有异步方法
    //3.1.执行3次循环
    dispatch_group_async(group,queue,^{
        for (NSInteger i = 0; i< 3; i++){
            NSLog(@"group-01 - %@", [NSThread currentThread]);
        }
    });
    //3.2.主队列执行8次循环
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        for (NSInteger i=0;i<8;i++) {
            NSLog(@"group-02 - %@", [NSThread currentThread]);
        }
    });
    //3.3.执行5次循环
    dispatch_group_async(group, queue, ^{
        for(NSInteger i=0;i<5;i++) {
            NSLog(@"group-03 - %@", [NSThread currentThread]);
        }
    });
    //4.都完成后会自动通知
    dispatch_group_notify(group,dispatch_get_main_queue(),^{
        NSLog(@"完成 - %@", [NSThread currentThread]);
    });
}

dispatch_barrier 栅栏

// 1.barrier : 在barrier前面的先执行,然后再执行barrier,然后再执行barrier后面的 barrier的queue不能是全局的并发队列
dispatch_queue_t queue = dispatch_queue_create("11", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    for (int i = 0;  i < 100; i++) {
        NSLog(@"%@--1", [NSThread currentThread]);
    }
});

dispatch_async(queue, ^{
    for (int i = 0;  i < 100; i++) {
        NSLog(@"%@--2", [NSThread currentThread]);
    }
});

dispatch_barrier_async(queue, ^{
    for (int i = 0;  i < 100; i++) {
        NSLog(@"%@--3", [NSThread currentThread]);
    }
});

dispatch_async(queue, ^{
    for (int i = 0;  i < 100; i++) {
        NSLog(@"%@--4", [NSThread currentThread]);
    }
});

//    dispatch_after 延迟执行
    // 延迟执行
    // 方法1
    [self performSelector:@selector(run:) withObject:@"参数" afterDelay:2.0];

    // 方法2
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"%@", [NSThread currentThread]);
        }
    });

    // 方法3
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run:) userInfo:nil repeats:NO];

dispatch_once 整个程序运行中执行一次
// 整个程序中只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 一次性代码
});

思考题:以下函数输出的结果是什么?


image

以下的代码输出是什么呢


image

作用:实现某个类的单例对象

单例模式:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

//--------------单例模式--------------------

#if __has_feature(objc_instancetype)
#undef    AS_SINGLETON
#define AS_SINGLETON( ... ) \
- (instancetype)sharedInstance; \
+ (instancetype)sharedInstance;

#undef    DEF_SINGLETON
#define DEF_SINGLETON \
- (instancetype)sharedInstance \
{ \
return [[self class] sharedInstance]; \
} \
+ (instancetype)sharedInstance \
{ \
static dispatch_once_t once; \
static id __singleton__; \
dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; } ); \
return __singleton__; \
}
#undef    DEF_SINGLETON
#define DEF_SINGLETON( ... ) \
- (instancetype)sharedInstance \
{ \
return [[self class] sharedInstance]; \
} \
+ (instancetype)sharedInstance \
{ \
static dispatch_once_t once; \
static id __singleton__; \
dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; } ); \
return __singleton__; \
}

#else    // #if __has_feature(objc_instancetype)
#undef    AS_SINGLETON
#define AS_SINGLETON( __class ) \
- (__class *)sharedInstance; \
+ (__class *)sharedInstance;

#undef    DEF_SINGLETON
#define DEF_SINGLETON( __class ) \
- (__class *)sharedInstance \
{ \
return [__class sharedInstance]; \
} \
+ (__class *)sharedInstance \
{ \
static dispatch_once_t once; \
static __class * __singleton__; \
dispatch_once( &once, ^{ __singleton__ = [[[self class] alloc] init]; } ); \
return __singleton__; \
}

#endif    // #if __has_feature(objc_instancetype)

#import "gcdfunViewController.h"

#pragma mark - 单例模式(责任编辑:最模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容