IOS开发,多线程,GDC ,线程 详解

NSRunLoop 循环机制

NSRunTime 循环时刻

什么时候创建子线程是有条件的

1.进行大量数据运算   for

数据库查询 select 将 select放在子线程中

2.网络请求 异步(将异步放在子线程中)

IOS中关于UI的添加必须在主线程中操作

子线程不能修改,创建跟UI相关的任何内容

想要修改,必须在主线程上

进程号 : 线程号

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

NSString *str = @"点击测试";

NSString *str1 = @"等运算结果吧,别急";

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 75, 40)];

button.backgroundColor = [UIColor cyanColor];

[button setTitle:str forState:UIControlStateNormal];

[button setTitle:str1 forState:UIControlStateHighlighted];

[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button];

[button release];

}

- (void)buttonAction:(id)sender

{

unsigned long result = 0;

for (int i = 1; i < 635500000; i++) {

result = result+i;

NSLog(@"%lu", result);

}

}

NSThread 轻量级的多线程

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

NSString *str = @"点击测试";

NSString *str1 = @"等运算结果吧,别急";

UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 75, 40)];

button.backgroundColor = [UIColor cyanColor];

[button setTitle:str forState:UIControlStateNormal];

[button setTitle:str1 forState:UIControlStateHighlighted];

[button addTarget:self action:@selector(createThread:) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button];

[button release];

}

//NSThread方法创建子线程  这个只是告诉哪个方法在子线程中跑

- (void)createThread:(id)sender

{

//NSThread第一种写法

//    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction) object:NULL];

//    [thread start];

//    [thread release];

//NSThread第二种写法

[NSThread detachNewThreadSelector:@selector(threadAction) toTarget:self withObject:NULL];

}

- (void)threadAction

{

//创建autoreleasepool方法一

//    @autoreleasepool {

//        unsigned long result = 0;

//        for (int i = 1; i < 635500000; i++) {

//            result = result+i;

//            NSLog(@"%lu", result);

//        }

//    }

//创建autoreleasepool  方法二  只能在MRC中 使用

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

//unsigned 无符号的意思  unsigned long 无符号长整形

unsigned long result = 0;

for (int i = 1; i < 635500000; i++) {

result = result+i;

NSLog(@"%lu", result);

}

[pool release];  //NSAutoreleasePool  释放池的第一种方法

//    [pool drain]      //NSAutoreleasePool  释放池的第二种方法

}

NSOperation

NSOperationQueue 称为线程队列

OperationQueue才是多线程

#pragma mark -

#pragma mark Operation创建子线程

#import "Operation.h"

.

.

.

.

.

.

- (void)createOperation

{

NSLog(@"%s",__func__);

Operation *operation = [[Operation alloc] init];

Operation *operation1 = [[Operation alloc] init];

Operation *operation2 = [[Operation alloc] init];

Operation *operation3 = [[Operation alloc] init];

Operation *operation4 = [[Operation alloc] init];

operation.delegate = self;

//    [operation start];

//下面这两行  等于start的功能    主要是看进程号,看进程号跟主线程的进程号是不是一样  来确定是否在主线程上

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue setMaxConcurrentOperationCount:2];//限制子线程的最大并行数

[queue addOperation:operation];

[queue addOperation:operation1];

[queue addOperation:operation2];

[queue addOperation:operation3];

[queue addOperation:operation4];

[queue release];

//Operation 要和 OperationQueue  成对使用  单独使用没有用

//OperationQueue才是多线程  operation只是多线程中的一个方法

}

- (void)sendImage:(UIImage *)image

{

UIImageView *aImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, self.view.frame.size.height)];

aImage.image = image;

[self.view addSubview:aImage];

[aImage release];

}

#import

@protocol OperationDelegate;

@interface Operation : NSOperation

@property(nonatomic , assign) iddelegate;

@end

@protocol OperationDelegate

- (void)sendImage:(UIImage *)image;

@end

#import

@protocol OperationDelegate;

@interface Operation : NSOperation

@property(nonatomic , assign) iddelegate;

@end

@protocol OperationDelegate

- (void)sendImage:(UIImage *)image;

@end

#import "Operation.h"

@implementation Operation

- (void)dealloc

{

[super dealloc];

}

- (instancetype)init

{

self = [super init];

if (self) {

}

return self;

}

- (void)main

{

//    @autoreleasepool {

//        NSLog(@"%@",[NSThread currentThread]);

//        unsigned long result = 0;

//        for (int i = 1; i < 10; i++) {

//            result = result+i;

//            NSLog(@"%lu", result);

//        }

//    }

NSURL * url = [NSURL URLWithString:@" 图片网址(自己写,博客上不让发链接) "];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *aImage = [UIImage imageWithData:data];

//判断代理人是否能够调用这个方法

if ([self.delegate respondsToSelector:@selector(sendImage:)]) {

//        [self.delegate sendImage:aImage];

[self performSelectorOnMainThread:@selector(finished:) withObject:aImage waitUntilDone:YES];

}

}

- (void)finished:(UIImage *)aimage

{

[self.delegate sendImage:aimage];

}

@end

NSObject 创建子线程

#pragma mark -

#pragma mark NSObject创建子线程

- (void)objectThread

{

[self performSelectorInBackground:@selector(threadAction) withObject:NULL];

}

NSthread

NSOperation

NSObject

以上三个是IOS4.0以前经常用的

他们返回主线程的方法就是用

[performSelectorInBackground: withObject: ]

________________________________________________________________________________________________________________________________

GCD(Grand Central Dispatch)

Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。其建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。

GCD工作原理

1. GCD让程序平行排队执行任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。

2. 一个任务可以是一个函数(function)或者是一个block。 GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。

3. GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行

dispatch queue分为下面三种:

Serial:

又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。

Concurrent:

又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。

Main dispatch queue:

它是全局可用的serial queue,它是在应用程序主线程上执行任务的。

#import "MainViewController.h"

@interface MainViewController ()

@end

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

if (self) {

// Custom initialization

}

return self;

}

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view.

}

#pragma mark -

#pragma mark 创建一个同步的线程队列

- (void)createSerailGCD

{

//@""  是NSString类型  " " 是char类型

//创建一个变量名为queue的线程队列,队列的名字叫"first",队列类型为 同步的.

dispatch_queue_t queue = dispatch_queue_create("first", DISPATCH_QUEUE_SERIAL);

//异步执行线程队列

dispatch_async(queue, ^{

//在多线程中执行的代码

NSURL * url = [NSURL URLWithString:@" 图片地址 "];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *aImage = [UIImage imageWithData:data];

//异步返回主线程    dispatch_get_main_queue() 返回主线程的方法

dispatch_async(dispatch_get_main_queue(), ^{

UIImageView * imageView = [[UIImageView alloc] initWithImage:aImage];

[imageView release];

});

});

}

#pragma mark -

#pragma mark 创建一个并发的线程队列

- (void)createConcurrentGCD

{

//并发中,下面注释这段可以省略 用别的代替  上面跟下面的效果是一样的

//    dispatch_queue_t queue = dispatch_queue_create("second", DISPATCH_QUEUE_CONCURRENT);

//    dispatch_async(queue, ^{

//

//    });

//由这句话代表上面注释这段话  DISPATCH_QUEUE_PRIORITY_DEFAULT 默认的 级别高的先运行,级别低的后运行

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

//在多线程中执行的代码

NSURL * url = [NSURL URLWithString:@" 图片地址 "];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *aImage = [UIImage imageWithData:data];

//异步返回主线程

dispatch_async(dispatch_get_main_queue(), ^{

UIImageView * imageView = [[UIImageView alloc] initWithImage:aImage];

[imageView release];

});

});

}

@end

返回主线程方法

返回主线程类型

方法:

GCD

dispatch_get_main_queue()

NSObject

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

线程互斥场景

线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。因此需要加上互斥锁来进行顺序访问,最具有代表性的就是买票系统!

条件锁

NSConditionLock称为条件锁,它的应用场景通常为线程同步。

当我们在使用多线程的时候,有时一把只会lock和unlock的锁未必就能完全满足我们的使用。因为普通的锁只能关心锁与不锁,而不在乎用什么钥匙才能开锁,而我们在处理资源共享的时候,多数情况是只有满足一定条件的情况下才能打开这把锁,比如生产者和消费者!

递归锁

NSRecursiveLock称为递归锁

平时我们在代码中使用锁的时候,最容易犯的一个错误就是造成死锁,而容易造成死锁的一种情形就是在递归或循环中。

NSRecursiveLock

在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了,那么如何在递归或循环中正确的使用锁呢?此处的“锁”如果换用NSRecursiveLock对象,问题便得到解决了,NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得

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

推荐阅读更多精彩内容