day6---多线程

  1. 进程和线程
      进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位;线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位。线程的划分尺度小于进程,这使得多线程程序的并发性高;进程在执行时通常拥有独立的内存单元,而线程之间可以共享内存。使用多线程的编程通常能够带来更好的性能和用户体验,但是多线程的程序对于其他程序是不友好的,因为它可能占用了更多的CPU资源。当然,也不是线程越多,程序的性能就越好,因为线程之间的调度和切换也会浪费CPU时间。
  2. 串行和并行
      当一个线程执行多个任务,会采用执行完一个再执行下一个的方式,这种执行任务的方式称为串行;多个线程分担多个任务,不同的任务同时执行,这种执行任务的方式称为并发。
  3. 同步和异步
      同步是指当前一个任务未能完成时,后一个任务被阻塞;异步可以理解为不同的任务在不同的线程中执行,当开辟的子线程(工作线程)发生阻塞,主线程或其他线程不会受到影响。

说明:异步和并发的概念不完全相同,异步强调解决主线程阻塞的问题,而并发一般指子线程(工作线程)之间的关系,多个工作线程分担任务称为并发执行任务。

  iOS开发中实现多线程的方式很多,包括:

  • NSThread类:线程,此种方式是轻量级的线程机制,但需要自行管理线程的生命周期,线程同步等问题,同步锁会产生系统开销。
  • NSThread类:
    线程,此种方式是轻量级的线程机制,但需要自行管理线程的生命周期,线程同步等问题,同步锁会产生系统开销。

    1.创建线程的三种方式:
    //第一种创建方法
    //第一个参数 执行线程的对象
    //第二个参数 选择器
    //第三个参数 传入的参数
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    //标记执行某一线程任务时的线程名字
    thread.name = @"线程1";
    //开启线程
    [thread start];

    //第二种方法:类方法创建 【不返回任何数据类型】
    [NSThread detachNewThreadSelector:@selector(run1:) toTarget:self withObject:@"33333"];

    //第三种方法:创建一个在后台的线程
    [self performSelectorInBackground:@selector(run2) withObject:nil];

2.给线程加锁的三种方式
1)lock三个步骤:
//第一步:初始化一个锁的对象;
//锁是为了保障访问同一数据时 数据的安全性
_lock = [[NSLock alloc] init];

//第二步:给子线程加锁,不允许其它线程访问;
[_lock lock];

 //第三部:子线程结束,给子线程解锁;允许其它线程访问;
 [_lock unlock];

2)sychronized方法:    【将子线程要执行的操作写在大括号中】
//nonatomic非原子性     atomic 原子性(对同一时间访问的对象进行保护)
//相比于lock 而言,它只能锁住一次,不能重复加锁
//一旦锁住则知道线程完毕才允许另一个线程访问
@synchronized (self)    【这个方法直接写在子线程的实现方法中】
{

}

3)condition方法三个步骤:【和lock类似,但是多了暂停功能】
    初始化
        _condition = [[NSCondition alloc] init];
            上锁
        //condition上锁和lock相似
        [_condition lock];
            解锁
        [_condition unlock];

condition的暂停功能:
//暂停判断,程序一进来就做判断;
if (_tickets == 90) 【给暂停条件】
{
//暂停
[_condition wait];
}

    【什么时候解除暂停】

[self performSelector:@selector(until) withObject:nil afterDelay:3];
-(void)until
{
//唤醒线程
[_condition signal];

            }

3.子线程给主线程传值的两种方法: 【系统自带的方法】
//************ 给主线程传数据 ****************,
//方法一
//第一个参数:选择器
//第二个参数:传参
//第三个参数:等待是否执行完毕
NSLog(@"000000000000000000000");
[self performSelectorOnMainThread:@selector(log:) withObject:@"1111111" waitUntilDone:YES];
NSLog(@"2222222222222222222222");

//方法二
[self performSelector:@selector(log:) onThread:[NSThread mainThread] withObject:@"444444" waitUntilDone:NO];

二、operation
1)创建operation的两种方法
//************ 创建operation的两种方式 **************
//第一个参数:表示调起线程的对象
//第二个参数:选择器
//第三个参数:传入的参数

//第一种方法
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(log) object:nil];
[operation start];              【创建operation对象,开启对象】



//第二种方法  
    【这种方法创建的operation对象可以另外给线程添加任务】
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    
    NSLog(@"2222222222");
}];
[operation1 addExecutionBlock:^{        【另外添加任务的方法】
    
    //线程添加任务
    NSLog(@"3333333");
    
}];

[operation1 start];

2)将operation对象添加到队列中
NSOperationQueue *q = [[NSOperationQueue alloc] init]; 【创建队列】

//先给依赖关系,即先排好顺序;
[operation1 addDependency:operation];                   【先排序】
[operation2 addDependency:operation1];  
[operation3 addDependency:operation2];


//在添加到队列中;
[q addOperation:operation];
[q addOperation:operation1];                        【添加operation】
[q addOperation:operation2];
[q addOperation:operation3];



//最大并行数 如果设置为1  表示串行
[q setMaxConcurrentOperationCount:1];

3)用多线程申请数据
-(void)loadData
{
_imageArry = [NSMutableArray array];
NSMutableArray *qArr = [NSMutableArray array];

for (int i=0; i<_imgArr.count; i++) {
    
    NSBlockOperation *operation = [NSBlockOperation     【创建多个线程】blockOperationWithBlock:^{
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:_imgArr[i]]]];
        [_imageArry addObject:image];
        
        if (i==_imgArr.count-1) {       
                                【利用子线程传值的方法回到主线程刷新数据】
            [_tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
            
            
            //下面这个回到主线程的方法是在reloadData刷新数据借宿后调用的
            dispatch_async(dispatch_get_main_queue(), ^{    
        【数据刷新成功以后调用这个方法,检测什么时候刷新结束】
                NSLog(@"刷新结束");
            });
        }
        
    }];
    
    if (i>0) {
            【给子线程添加依赖关系,即给子线程排序】
        [operation addDependency:(NSOperation *)[qArr lastObject]];
    }
    
    [qArr addObject:operation];
}

NSOperationQueue *q = [[NSOperationQueue alloc] init];
for (int i= (int)qArr.count-1; i>=0; i--) {
    
    [q addOperation:qArr[i]];           【将子线程添加到队列中】
    
}

[q setMaxConcurrentOperationCount:1];

}

三、GCD
3 GCD
1.什么是GCD?
全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
纯C语言,提供了非常多强大的函数

2.GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
//1.延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// NSLog(@"11111");
});

//2.单例的创建
[self createManager];

-(void)createManager
{
//2.单例的创建
//创建一个执行一次的静态的线程
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//执行线程
manager = [[UIViewController alloc] init];

});

NSLog(@"----------%p",manager);

}

//3.进入异步 自动进入ios队列等待执行.开辟线程做某件事
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
    
});


//回到主线程做某件事
dispatch_async(dispatch_get_main_queue(), ^{
    
});


//4.先在异步做某件事情,然后回到主线程再做其他事情;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
    //回到主线程做某件事
    dispatch_async(dispatch_get_main_queue(), ^{
        
    });
    
});

//5.自定义线程,创建一个线程;
dispatch_queue_t urlq = dispatch_queue_create("1111", NULL);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, urlq, ^{
    NSLog(@"222222");
});
dispatch_group_async(group, urlq, ^{
    NSLog(@"333333");
});
dispatch_group_notify(group, urlq, ^{
    NSLog(@"000099999");
});
dispatch_group_async(group, urlq, ^{
    NSLog(@"4444444");
});
dispatch_group_async(group, urlq, ^{
    NSLog(@"5555555");
});



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

推荐阅读更多精彩内容