Thread 多线程
Thread 多线程
1.多线程的概念
程序: 代码编译后, 形成执行文件
进程: 程序运行起来, 就是进程, 进程提供程序运行所需的端口等
线程: 分配资源
进程中至少要有一个线程(主线程), 如果主线程阻塞, 程序就会假死; 如果主线程停止运行, 程序将终止
2.没有使用多线程的应用, 有什么问题?
当处理复杂的数据操作时, 就会阻塞主线程
3.多线程的方式
a.NSObject
b.NSThread
c.NSOperationQueue
d.GCD
4.需不需要把所有的操作都放在子线程上?(主线程和子线程的区别)
a.能够调度资源大小不一样(主:10M, 子:5M)
b.子线程不能释放通过便利构造器创建的对象, 原因: 子线程没有自动释放池, autorelease的对象无法得到释放
c.刷新UI的操作必须在主线程中执行, 原因: 在子线程中刷新UI会失败
5.多线程的优缺点
优点: 可以为主线程分担操作, 避免出现主线程阻塞; 执行效率高
缺点: 资源消耗高; 资源抢夺; 需要管理
6.多个线程使用同一块资源时, 会出现资源抢夺, 解决方案: 当操作这块资源时, 加锁, 离开时, 解锁; 保证同一个时刻只能有一个线程操作资源
在story中添加button, 关联方法
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(rotation) userInfo:nil repeats:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)rotation {
[UIView beginAnimations:@"旋转" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.15];
self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, M_PI_4);
[UIView commitAnimations];
}
- (IBAction)server:(id)sender {
@autoreleasepool {
for (NSInteger i = 1; i <= 1000; i++) {
@autoreleasepool {
NSString *string = [NSString stringWithFormat:@"接了%ld个客人", i];
NSLog(@"%@", string);
}
//线程休眠
[NSThread sleepForTimeInterval:1];
}
NSThread *currentThread = [NSThread currentThread];
NSLog(@"%@", currentThread);
}
}
NSObject中提供一些和线程相关的方法
在主线程执行某些方法
[self performSelectorOnMainThread: withObject: waitUntilDone:]
在后台执行某些方法(在后台的子线程执行)
- (IBAction)serverWithNSObject:(id)sender {
// 在后台执行某些方法(在后台的子线程执行)
[self performSelectorInBackground:@selector(server:) withObject:nil];
}
NSThread, 线程类, 继承于NSObject
- (IBAction)serverWithNSThread:(id)sender {
//获取主线程
NSThread *mainThread = [NSThread mainThread];
NSLog(@"%@", mainThread);
//线程所占的栈区大小, 4KB
NSLog(@"%lu", mainThread.stackSize);
//创建子线程
NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(server:) object:self];
subThread.name = @"子线程";
// [subThread start];
NSLog(@"%@", subThread);
NSLog(@"%lu", subThread.stackSize);
//创建线程
[NSThread detachNewThreadSelector:@selector(server:) toTarget:self withObject:nil];
//线程休眠
// [NSThread sleepForTimeInterval:<#(NSTimeInterval)#>]
//获取当前线程
// NSThread *currentThread = [NSThread currentThread];
// NSLog(@"%@", currentThread);
}
NSOperationQueue, 操作队列类, 继承于NSObject, 操作队列内存放各种操作, 这些操作最终在操作队列对应的线程上执行
队列, 存放数据的方式: 先进先出(FIFO)
NSOperation, 操作类, 可以存放在操作队列中, 抽象类, 操作只能执行一次, 它的子类有:
NSInvocationOperation
NSBlockOperation
- (void)eat {
for (NSInteger i = 1; i < 100; i++) {
NSLog(@"吃了%ld只龙虾", i);
}
}
- (IBAction)serverWithNSOperationQueue:(id)sender {
NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(eat) object:nil];
//执行操作(在主线程中执行)
// [invocation start];
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = 1; i <= 100; i++) {
NSLog(@"喝了%ld罐青岛啤酒", i);
}
}];
// [block start];
//操作建立依赖关系
[invocation addDependency:block];
//创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//最大并发数
//并发数为1的队列, 叫串行队列
//并发数大于1的队列, 叫并发队列
queue.maxConcurrentOperationCount = 1;
//向队列中添加操作(只有把操作添加到队列, 操作就会在队列对应的线程中执行)
// [queue addOperation:invocation];
// [queue addOperation:block];
//同时添加多个操作
[queue addOperations:@[invocation, block] waitUntilFinished:NO];
//主队列, 绑定主线程
// NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
}
GCD, Grand central Dispatch, 大中央调度, 多线程优化技术, 通过C语言实现, 执行效率高
- (IBAction)serverWithGCD:(id)sender {
三种队列
1.主调队列, 绑定主线程, 并发数为1
dispatch_queue_t: 队列数据类型
mianQueue: 变量名
dispatch_get_main_queue: 调用函数
dispatch_queue_t mianQueue = dispatch_get_main_queue();
NSLog(@"%@", mianQueue);
2.全局队列, 绑定子线程, 并发队列
参数1: 优先级
参数2: 预留参数, 为未来做准备, 一般写0
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"%@", globalQueue);
3.自定义队列, 绑定子线程
参数1: 队列的标识符, 通过调试工具可以查看
参数2: 串行或并发
dispatch_queue_t customQueu = dispatch_queue_create("com.huige", DISPATCH_QUEUE_SERIAL);
NSLog(@"%@", customQueu);
在队列中, 执行某些操作, 有两种方式:
1.同步执行
参数1: 操作执行队列
参数2: block, 写你想要执行的操作
dispatch_sync(globalQueue, ^{
for (NSInteger i = 1; i <= 100; i++) {
NSLog(@"%ld", i);
}
});
2.异步执行
dispatch_async(mianQueue, ^{
for (NSInteger i = 1; i <= 100; i++) {
NSLog(@"笑场%ld次", i);
}
});
延迟多少秒执行某些操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"再见");
});
// dispatch_after(<#dispatch_time_t when#>, <#dispatch_queue_t queue#>, <#^(void)block#>)
}
创建单例
Singleton.h
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
+ (Singleton *)sharedSingleton;
@end
Singleton.m #import "Singleton.h" @implementation Singleton 1.主线程创建 + (Singleton *)sharedSingleton { static Singleton *singleton = nil; if (singleton == nil) { singleton = [[Singleton alloc] init]; } return singleton; }
2.互斥锁 + (Singleton *)sharedSingleton { static Singleton *singleton = nil; //互斥锁 @synchronized(self) { if (singleton == nil) { singleton = [[Singleton alloc] init]; } } return singleton; }
3.dispatch_once 保证代码只执行一次
+ (Singleton *)sharedSingleton {
static Singleton *singleton = nil;
//保证代码只执行一次, dispatch_once
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ singleton = [[Singleton alloc] init];
});
return singleton;
}
@end
多线程购票
效果图:
具体代码: 在storyboard中添加一个label和开始售票的button, 关联方法和属性
#import "TicketViewController.h"
@interface TicketViewController ()
- (IBAction)start:(id)sender;
@property (strong, nonatomic) IBOutlet UILabel *label;
@property (nonatomic, assign) NSInteger totalCount;//总票数
@property (nonatomic, assign) NSInteger saleCount;//卖出的票数
@property (nonatomic, strong) NSLock *lock;//锁
@end
@implementation TicketViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.totalCount = 100;
self.saleCount = 0;
self.lock = [[NSLock alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)refreshUI {
[UIView transitionWithView:self.label duration:0.2 options:UIViewAnimationOptionTransitionCurlUp animations:^{
self.label.text = [NSString stringWithFormat:@"%ld", self.totalCount];
} completion:^(BOOL finished) {
[self.lock unlock];
}];
}
- (void)sale {
while (YES) {
[NSThread sleepForTimeInterval:0.5];
[self.lock lock];
if (self.totalCount > 0) {
self.totalCount--;
//在主线程中执行
[self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:NO];
self.saleCount++;
NSLog(@"%@, 卖了%ld张票, 剩余%ld张票", [NSThread currentThread], self.saleCount, self.totalCount);
} else {
NSLog(@"票卖完了, 明年再回家吧!");
return;
}
}
}
- (IBAction)start:(id)sender {
//售票窗口(子线程)
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
thread1.name = @"窗口1";
[thread1 start];
// 第二个售票窗口
NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sale) object:nil];
thread2.name = @"窗口2";
[thread2 start];
}
@end