多线程使用情况:
1、耗时,而且很难知道什么时候会结束(如下载视频小说等)
2、游戏中播放声音
每个进程启动之后,会有一个主线程
遇到耗时的操作时,新建线程去执行,可以保证主线程流畅
主线程是其他线程的最终父线程,
所有界面的显示操作必须在主线程进行
后台线程无法更新UI界面和响应用户点击事件
系统中每一个进程都有自己独立的虚拟内存空间,而同一个进程中多个线程公用进程的内存空间
每创建一个新的线程,都会消耗一定的内存和CPU时间,要控制线程执行顺序
当多个线程对同一个资源出现争夺时要注意线程安全问题
主线程堆栈大小是1M,第二个线程开始512kb
NSLog(@"大任务%@",[NSThread currentThread]);
<NSThread: 0x10950f2f0>{name = (null), num = 1}
num = 1说明是主线程
多线程是异步的,谁先谁后很难判断,不因代码书写先后改变
线程休眠,[NSThread sleepForTimeInterval:2];值适用于开发调试使用
下面上代码验证例子:
//
// MainViewController.m
// 多线程-01.大任务
//
// Created by admin on 14-10-9.
// Copyright (c) 2014年 admin. All rights reserved.
//
#import "MainViewController.h"
/*
1、[NSThread currentThread]可以返回当前的运行线程
num = 1 说明是主线程
在任何多线程技术中(NSThread,NSOperation,GCD)都可以调用此方法查看明细
2、新建后台线程,[self performSelectorInBackground:@selector(bigTask) withObject:nil];
一般不在主线程中是不可以修改UI内容的,但是performSelectorInBackground可以修改
尽管如此,我们还是不应该在其他线程中修改UI内容
3、更新界面
使用performSelectorOnMainThread可以在主线程上执行任务。
NSObject对象都可以调用此方法
4、线程任务要含在自动释放池里面,否则容易引起内存泄露,而且很难发现
*/
@interface MainViewController ()
@property (weak, nonatomic) UIImageView *imageView;
@end
@implementation MainViewController
#pragma mark - 耗时操作
- (void)bigTask
{
for (NSInteger i = 0; i < 500; i++) {
NSString *str = [NSString stringWithFormat:@"字符串%zi",i];
<span style="white-space:pre"> </span>NSLog(@"%@",str);
}
NSLog(@"大任务%@",[NSThread currentThread]);
}
#pragma mark - 不耗时操作
- (void)smallTask
{
NSLog(@"小任务%@",[NSThread currentThread]);
NSString *str = nil;
for (NSInteger i = 0; i < 30000; i++) {
str = [NSString stringWithFormat:@"****************%zi",i];
}
NSLog(@"%@",str);
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn1 setFrame:CGRectMake(110, 100, 100, 40)];
[btn1 setTitle:@"大事件" forState:UIControlStateNormal];
[btn1 addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn1];
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn2 setFrame:CGRectMake(110, 200, 100, 40)];
[btn2 setTitle:@"小事件" forState:UIControlStateNormal];
[btn2 addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn2];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(110, 260, 100, 100)];
UIImage *image = [UIImage imageNamed:@"头像1.png"];
[imageView setImage:image];
self.imageView = imageView;
[self.view addSubview:imageView];
}
- (void)button1
{
//在后台调用耗时操作
//会新建一个后台线程,并且在该线程中执行调用方法
[self performSelectorInBackground:@selector(bigTask) withObject:nil];
// [self bigTask];
//不等上句话执行完就开始执行,因为是一个执行流,上一句话重新开了一个进程
NSLog(@"@@@@@@@@@@%@",[NSThread currentThread]);
//可以改变UI,但是不建议这么使用,在主进程中改UI
UIImage *image = [UIImage imageNamed:@"头像2.png"];
// [self.imageView setImage:image];
@autoreleasepool {//main.m里面的只能管理主线程的,如果涉及到其他线程的最后用自动释放池包含一下
//在主线程中修改image
// [self performSelectorOnMainThread:@selector(changedImage:) withObject:image waitUntilDone:YES];
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
}
- (void)button2
{
[self smallTask];
}
- (void)changedImage:(UIImage *)image
{
NSLog(@"修改图片%@",[NSThread currentThread]);
[self.imageView setImage:image];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
如果button1的操作不在后台中操作,大事件点击后要等所有的打印操作完成之后才能点击小事件
打印是非常耗时的操作,所以在程序正式运行时最好把nslog关掉
优点:
1、使用简单,轻量级;
缺点:
1、缺点是不能控制线程的执行顺序。