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操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得