标签:
多线程概念详解
什么是进程?
什么是线程?
进程和线程之间的关系
什么是CPU?
多线程的原理
多线程优点
多线程的缺点
主线程
IOS中多线程的实现方案
方案 |
简介 |
语言 |
线程生命周期 |
使用频率 |
pthread |
|
C |
程序员管理 |
几乎不用 |
NSThread |
|
OC |
程序员管理 |
偶尔使用 |
GCD |
|
C |
自动管理 |
经常使用 |
NSOperation |
|
OC |
自动管理 |
经常使用 |
NSThread使用
创建线程的种方式
NSThread 是iOS提供的轻量级开发,使用起来也相对简单
为什么要使用NSThread ?
NSThread-Demo:
//点击下载图片
- (IBAction)downLoaon:(id)sender {
//通过NSThread对象方法
//[self objectMethod];
//通过NSThread类方法
//[self classMethod];
//通过NSObject的方法
[self extendedMethod];
}
//通过NSObject的方法去下载图片
- (void)extendedMethod{
//通过NSObject分类方法
[self performSelectorInBackground:@selector(downLoadImage) withObject:nil];
}
//通过NSThread类方法去下载图片
- (void)classMethod{
//NSThread类方法
[NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
}
//通过NSThread对象方法去下载图片
- (void)objectMethod{
//创建一个程序去下载图片
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(downLoadImage) object:nil];
NSLog(@"downLoaon:%@",[NSThread currentThread]);//主线程
//开启线程
[thread start];
}
//下载图片
- (void)downLoadImage{
//请求图片资源
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//模拟下载延迟
[NSThread sleepForTimeInterval:10];
//将资源转换为二进制
NSData *data=[NSData dataWithContentsOfURL:url];
NSLog(@"downLoadImage:%@",[NSThread currentThread]);//在子线程中下载图片
//在主线程更新UI
[self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
}
//更新imageView
- (void)updateImage:(NSData *)data{
NSLog(@"updateImage:%@",[NSThread currentThread]);//在主线程中更新UI
//将二进制数据转换为图片
UIImage *image=[UIImage imageWithData:data];
//设置image
self.imageView.image=image;
}
以上就是对NSThread三种使用的一个简单的Demo
线程状态
线程的属性(name)
线程的优先级(threadPriority)
栈区大小(stackSize)
是否是主线程(isMainThread)
线程间的通讯
GCD的使用
GCD 核心概念
阶段性小结
- 队列的选择
实际开发中,线程数量如何决定?
同步 & 异步
NSThread-Demo
//点击屏幕调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"touchesBegan开始执行");
//同步调用
[self start];
//异步调用
//[self performSelectorInBackground:@selector(start) withObject:nil];
NSLog(@"touchesBegan执行结束");
}
//开始执行
- (void)start{
NSLog(@"start开始执行");
NSLog(@"start当前线程:%@",[NSThread currentThread]);
//延迟5秒调用
[NSThread sleepForTimeInterval:5];
NSLog(@"start执行完毕");
}
执行以上代码,发现当同步的时候执行的结果为:
2015-11-26 18:17:29.621 GCD同步异步[1267:159851] touchesBegan开始执行
2015-11-26 18:17:29.621 GCD同步异步[1267:159851] start开始执行
2015-11-26 18:17:29.621 GCD同步异步[1267:159851] start当前线程:0x7fec12e01780>{number = 1, name = main}
2015-11-26 18:17:34.627 GCD同步异步[1267:159851] start执行完毕
2015-11-26 18:17:34.627 GCD同步异步[1267:159851] touchesBegan执行结束
执行以上代码,发现当异步的时候执行的结果为:
2015-11-26 18:23:10.846 GCD同步异步[1282:163977] touchesBegan开始执行
2015-11-26 18:23:10.847 GCD同步异步[1282:163977] touchesBegan执行结束
2015-11-26 18:23:10.848 GCD同步异步[1282:164254] start开始执行
2015-11-26 18:23:10.848 GCD同步异步[1282:164254] start当前线程:0x7fa778f0f0f0>{number = 2, name = (null)}
2015-11-26 18:23:15.849 GCD同步异步[1282:164254] start执行完毕
结论:同步是从上到下有顺序的执行,异步则不是
GCD-Demo
//点击屏幕的时候调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//异步
//[self asyncMethod];
//同步
[self syncMethod];
}
//异步的时候调用
- (void)asyncMethod{
//获取全局队列
dispatch_queue_t queue=dispatch_get_global_queue(0, 0);
//创建任务
void(^task)()=^{
NSLog(@"asyncMethod:%@",[NSThread currentThread]);
};
//执行任务
dispatch_async(queue, task);
NSLog(@"end");
}
//同步的时候调用
- (void)syncMethod{
//获取全局队列
dispatch_queue_t queue=dispatch_get_global_queue(0, 0);
//创建任务
void(^task)()=^{
NSLog(@"syncMethod:%@",[NSThread currentThread]);
};
//执行任务
dispatch_sync(queue, task);
NSLog(@"end");
}
执行以上代码,发现当同步的时候执行的结果为:
2015-11-26 18:40:55.419 GCD中的同步和异步[1361:177648] syncMethod:0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.419 GCD中的同步和异步[1361:177648] end
2015-11-26 18:40:55.667 GCD中的同步和异步[1361:177648] syncMethod:0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.667 GCD中的同步和异步[1361:177648] end
2015-11-26 18:40:55.926 GCD中的同步和异步[1361:177648] syncMethod:0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.927 GCD中的同步和异步[1361:177648] end
执行以上代码,发现当异步的时候执行的结果为:
2015-11-26 18:41:36.351 GCD中的同步和异步[1370:178492] asyncMethod:0x7fc941e02a70>{number = 2, name = (null)}
2015-11-26 18:41:36.351 GCD中的同步和异步[1370:178425] end
2015-11-26 18:41:36.576 GCD中的同步和异步[1370:178425] end
2015-11-26 18:41:36.576 GCD中的同步和异步[1370:178492] asyncMethod:0x7fc941e02a70>{number = 2, name = (null)}
2015-11-26 18:41:36.810 GCD中的同步和异步[1370:178425] end
2015-11-26 18:41:36.810 GCD中的同步和异步[1370:178492] asyncMethod:0x7fc941e02a70>{number = 2, name = (null)}
和NSThread对比可以发现
使用GCD下载图片
//点击下载图片
- (IBAction)downLoaon:(id)sender {
//获取全局队列
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//异步下载图片
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//将资源转换为二进制
NSData *data=[NSData dataWithContentsOfURL:url];
//将二进制转化为图片
UIImage *image=[UIImage imageWithData:data];
//获取主队列,更新UI
dispatch_sync(dispatch_get_main_queue(), ^{
//给图片控件赋值
self.imageView.image=image;
});
});
}
串行队列
串行队列特点:
队列创建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
串行队列同步&异步Demo
//点击屏幕的时候调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//同步执行
//[self syncMethod];
//异步执行
[self asyncMethod];
}
//同步
- (void)syncMethod{
//创建队列
dispatch_queue_t queue=dispatch_queue_create("同步", DISPATCH_QUEUE_SERIAL);
//执行任务
for (int i=0; i<</span>6; i++) {
NSLog(@"1--->%d",i);
dispatch_sync(queue, ^{
NSLog(@"2--->%d---%@",i,[NSThread currentThread]
);
});
}
NSLog(@"end");
}
//异步
- (void)asyncMethod{
//创建队列
dispatch_queue_t queue=dispatch_queue_create("异步", DISPATCH_QUEUE_SERIAL);
//执行任务
for (int i=0; i<</span>6; i++) {
NSLog(@"1--->%d",i);
dispatch_async(queue, ^{
NSLog(@"2--->%d---%@",i,[NSThread currentThread]
);
});
}
NSLog(@"end");
}
串行队列同步执行结果:
2015-11-26 19:12:20.876 串行队列的同步和异步[1520:204175] 1--->0
2015-11-26 19:12:20.877 串行队列的同步和异步[1520:204175] 2--->0---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.877 串行队列的同步和异步[1520:204175] 1--->1
2015-11-26 19:12:20.877 串行队列的同步和异步[1520:204175] 2--->1---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.877 串行队列的同步和异步[1520:204175] 1--->2
2015-11-26 19:12:20.877 串行队列的同步和异步[1520:204175] 2--->2---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 1--->3
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 2--->3---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 1--->4
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 2--->4---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 1--->5
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] 2--->5---0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行队列的同步和异步[1520:204175] end
串行队列异步执行结果:
2015-11-26 19:12:41.923 串行队列的同步和异步[1529:204751] 1--->0
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204751] 1--->1
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204829] 2--->0---0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204751] 1--->2
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204829] 2--->1---0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204751] 1--->3
2015-11-26 19:12:41.924 串行队列的同步和异步[1529:204829] 2--->2---0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204751] 1--->4
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204829] 2--->3---0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204751] 1--->5
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204829] 2--->4---0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204751] end
2015-11-26 19:12:41.925 串行队列的同步和异步[1529:204829] 2--->5---0x7fc99970bbe0>{number = 2, name = (null)}
并发队列
并发队列特点:
队列创建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
并行队列同步&异步Demo
//点击屏幕的时候调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//同步
//[self syncMethod];
//异步
[self asyncMethod];
}
//异步
- (void)asyncMethod{
//并发队列
dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//创建任务
for(int i=0; i<</span>6 ;i++ ){
dispatch_async(queue, ^{
NSLog(@"async--->%d---%@",i,[NSThread currentThread]);
});
}
NSLog(@"end");
}
//同步
- (void)syncMethod{
//并发队列
dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//创建任务
for(int i=0; i<</span>6 ;i++ ){
dispatch_sync(queue, ^{
NSLog(@"sync--->%d---%@",i,[NSThread currentThread]);
});
}
NSLog(@"end");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
并行队列同步执行结果:
2015-11-26 21:17:19.820 并发队列的同步与异步[1632:233685] sync--->0---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.820 并发队列的同步与异步[1632:233685] sync--->1---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并发队列的同步与异步[1632:233685] sync--->2---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并发队列的同步与异步[1632:233685] sync--->3---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并发队列的同步与异步[1632:233685] sync--->4---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并发队列的同步与异步[1632:233685] sync--->5---0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.822 并发队列的同步与异步[1632:233685] end
并行队列异步执行结果:
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234351] end
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234532] async--->3---0x7fa823c9a910>{number = 5, name = (null)}
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234425] async--->0---0x7fa823f0e720>{number = 3, name = (null)}
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234423] async--->2---0x7fa823e079f0>{number = 4, name = (null)}
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234533] async--->4---0x7fa823e000b0>{number = 6, name = (null)}
2015-11-26 21:17:45.000 并发队列的同步与异步[1641:234424] async--->1---0x7fa823d4d4e0>{number = 2, name = (null)}
2015-11-26 21:17:45.001 并发队列的同步与异步[1641:234534] async--->5---0x7fa823f0a290>{number = 7, name = (null)}
全局队列
主队列
//点击屏幕的时候调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//全局队列同步执行
[self global_queue_sync];
//全局队列异步执行
//[self global_queue_async];
//主队列同步执行
//[self main_queue_sync];
//主队列异步执行
//[self main_queue_async];
}
//主队列同步执行
- (void)main_queue_sync{
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; ++i) {
dispatch_sync(queue, ^{
NSLog(@"main_queue_sync%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//主队列异步执行
- (void)main_queue_async{
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; ++i) {
dispatch_async(queue, ^{
NSLog(@"main_queue_async%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//全局队列异步执行
- (void)global_queue_async{
//获取全局队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
//执行任务
for (int i = 0; i < 10; ++i) {
dispatch_async(q, ^{
NSLog(@"global_queue_async%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//全局队列同步执行
- (void)global_queue_sync{
//获取全局队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
//执行任务
for (int i = 0; i < 10; ++i) {
dispatch_sync(q, ^{
NSLog(@"global_queue_sync%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
全局队列同步执行结果:
2015-11-26 22:00:12.568 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->0
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->1
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->2
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->3
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->4
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->5
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->6
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->7
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->8
2015-11-26 22:00:12.569 全局队列与主队列[1895:266991] global_queue_sync0x7fb871d069e0>{number = 1, name = main}---->9
2015-11-26 22:00:12.570 全局队列与主队列[1895:266991] end
全局队列异步执行结果:
2015-11-26 22:01:01.565 全局队列与主队列[1908:268194] end
2015-11-26 22:01:01.566 全局队列与主队列[1908:268233] global_queue_async0x7f97fb607e80>{number = 2, name = (null)}---->1
2015-11-26 22:01:01.566 全局队列与主队列[1908:268234] global_queue_async0x7f97fb61f710>{number = 4, name = (null)}---->2
2015-11-26 22:01:01.566 全局队列与主队列[1908:268256] global_queue_async0x7f97fb63bec0>{number = 5, name = (null)}---->3
2015-11-26 22:01:01.566 全局队列与主队列[1908:268257] global_queue_async0x7f97fb7127d0>{number = 6, name = (null)}---->4
2015-11-26 22:01:01.566 全局队列与主队列[1908:268232] global_queue_async0x7f97fb70bde0>{number = 3, name = (null)}---->0
2015-11-26 22:01:01.566 全局队列与主队列[1908:268233] global_queue_async0x7f97fb607e80>{number = 2, name = (null)}---->5
2015-11-26 22:01:01.566 全局队列与主队列[1908:268234] global_queue_async0x7f97fb61f710>{number = 4, name = (null)}---->6
2015-11-26 22:01:01.566 全局队列与主队列[1908:268258] global_queue_async0x7f97fb442510>{number = 7, name = (null)}---->7
2015-11-26 22:01:01.566 全局队列与主队列[1908:268256] global_queue_async0x7f97fb63bec0>{number = 5, name = (null)}---->8
2015-11-26 22:01:01.567 全局队列与主队列[1908:268257] global_queue_async0x7f97fb7127d0>{number = 6, name = (null)}---->9
全局队列同步执行结果:
主队列和主线程相互等待会造成死锁,程序直接卡死
全局队列异步执行结果:
2015-11-26 22:02:09.057 全局队列与主队列[1935:269576] end
2015-11-26 22:02:09.058 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->0
2015-11-26 22:02:09.058 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->1
2015-11-26 22:02:09.058 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->2
2015-11-26 22:02:09.058 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->3
2015-11-26 22:02:09.058 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->4
2015-11-26 22:02:09.059 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->5
2015-11-26 22:02:09.059 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->6
2015-11-26 22:02:09.059 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->7
2015-11-26 22:02:09.059 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->8
2015-11-26 22:02:09.087 全局队列与主队列[1935:269576] main_queue_async0x7fadd850a320>{number = 1, name = main}---->9
NSOperation
NSOperation-Demo
//当点击屏幕的时候调用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//创建url
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//将资源转换为二进制
NSData *data=[NSData dataWithContentsOfURL:url];
//创建operation
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage:) object:data];
//执行操作
[operation start];
}
- (void)downLoadImage:(NSData *)data{
//将二进制转化为图片
UIImage *image=[UIImage imageWithData:data];
//显示图片
self.imageView.image=image;
}
将任务添加到队里中执行
- (void)touchesBegan:(NSSet*> *)touches withEvent:(UIEvent *)event{
//创建队列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
//创建任务
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:nil];
NSLog(@"1--->%@",[NSThread currentThread]);
//将任务添加到队列中
[operationQueue addOperation:operation];
}
//子线程中下载图片
- (void)downLoadImage{
//创建url
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//将资源转换为二进制
NSData *data=[NSData dataWithContentsOfURL:url];
NSLog(@"2--->%@",[NSThread currentThread]);
//将二进制转化为tup
UIImage *image=[UIImage imageWithData:data];
[self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES];
}
//主线程中更新图片
- (void)updateImage:(UIImage *)image{
NSLog(@"3--->%@",[NSThread currentThread]);
self.imageView.image=image;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
总结:无论使用何种方式进行多线程开发,都应该遵循一定的规则(尽可能将比较耗时比如去网络下载资源的操作放到子线程中执行),注重程序的执行效率以及用户的体验合理的使用多线程(线程虽好,可不要乱用噢).
以上Demo下载路径: https://github.com/chengaojian **
以上就是多线程中常用的一些介绍,由于时间比较仓促,很多例子都是现写,如果代码中存在错误,还请指出,谢谢.
标签:
原文地址:http://www.cnblogs.com/zhao-jie-li/p/5128488.html