[self performSelectorInBackground:@selector(downloadImage:) withObject:url];//系统自带的多线程方法,
- (void)downloadImage:(NSURL *)url {
//主线程的autoreleasepool无法管理多线程中的OC对象,因此需要在多线程的入口方法中添加autoreleasepool,就是多线程要自己主动放到自动释放池中,否则结束后无法自动释放
@autoreleasepool {
//for (int i = 0; i < 10; i++) {
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
//}
//所有UI界面的刷新都应该在主线程中完成,因为UI的绘制渲染引擎是工作在主线程中的,不能在多线程完成界面的刷新。
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
//把setImage:这个任务添加到主队列中执行,主队列中的任务都是在主线程中完成的。主队列是一个串行队列。这个方法是添加Image的方法,很多时候网络下载完成了,但是界面却没有刷新,这时候就要调用各种方法来刷新界面。
}
线程资源竞争:指的是某个内存只允许一个一个或一定数量的线程访问,只时候超过这个数量的访问则会导致出错。从而导致各种问题,为了避免这个问题就要加锁。
NSLock *_mutexLoc = [[NSLock alloc] init];//互斥锁,只有一把锁,而且没有标示。
while (_ticketCount > 0) {
//为了避免多个线程同时买票,造成资源竞争,因此需要加锁--》同步代码块
// [_mutexLock lock];//加锁
//对象级别锁:self是此锁的唯一标识,只有标识相同时,才满足互斥条件。对象级别锁就是整个对象给锁起来了,进去就锁起来,只是这个对象加锁,然后要加锁的任务完成了才允许解锁,再调用这个对象。
@synchronized(self) {
if (_ticketCount > 0) {
//开始买票,查询数据库
[NSThread sleepForTimeInterval:0.2];
NSLog(@"窗口%@卖出一张票,剩余票量为%li", [NSThread currentThread].name, --_ticketCount);
}
}
//解锁
// [_mutexLock unlock];//如果直接锁住,再解锁的话他只会进行一次,先用while进行判断
}
各种锁的介绍:
#import "ViewController.h"
@interface ViewController () {
NSLock *_mutexLock; //互斥锁
NSRecursiveLock *_rcsLock; //递归锁
NSConditionLock *_cdtLock; //条件锁
NSInteger _result;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_mutexLock = [[NSLock alloc] init];
_rcsLock = [[NSRecursiveLock alloc] init];
// [NSThread detachNewThreadSelector:@selector(callRecursiveMethod:) toTarget:self withObject:@5];
// [NSThread detachNewThreadSelector:@selector(callRecursiveMethod:) toTarget:self withObject:@4];
_cdtLock = [[NSConditionLock alloc] init];
[NSThread detachNewThreadSelector:@selector(conditionLockAction1) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(conditionLockAction2) toTarget:self withObject:nil];
}
- (void)conditionLockAction1 {
[NSThread sleepForTimeInterval:2];
for (NSInteger i = 0; i < 3; i++) {
//加锁
[_cdtLock lock];
NSLog(@"thread1:%li", i);
//释放锁,并设置condition属性的值为i
[_cdtLock unlockWithCondition:i];
//计算机内部还是有序的,内部有操作还是自己内部的近的,先去调用那把锁,多次则也有几率给下面的那把锁打开
}
}
- (void)conditionLockAction2 {
//当标识为2时同步代码段才能够执行,如果标识为其它数字则当前线程被block。
[_cdtLock lockWhenCondition:1];
NSLog(@"thread2");
[_cdtLock unlock];
}
- (void)callRecursiveMethod:(NSNumber *)value {
NSInteger n = [value integerValue];
[_rcsLock lock];
if (n != 0) {
NSLog(@"递归中,n的值为%li", n);
[self callRecursiveMethod:@(n - 1)];
}
[_rcsLock unlock];
}
#import "ViewController.h"
#define kMaxProductCount 10
@interface ViewController (){
NSMutableArray *productsArray; //库房
NSCondition *condition; //互斥锁和条件锁的结合
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
productsArray = [[NSMutableArray alloc] init];
condition = [[NSCondition alloc] init];
[NSThread detachNewThreadSelector:@selector(createProduct) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(createProduct) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(consumeProduct) toTarget:self withObject:nil];
//流程就是三个,然后前面两个动作是一样的所以随机一个先进入,后面那个则后进入,因为只有一把锁,所以只有一个工人能进去,而生产者或者消费者本身就是两种类型的工人,条件锁,系统也很智能,解锁的时候,先把近的解锁了再做另一个
//两个进程几乎同时进入,是否先打印只是根据里面内部的运行速度。然后先进的就锁住了
}
- (void)createProduct {
while (TRUE) {
[condition lock];
//如果库房已满,一直等待
while (productsArray.count == kMaxProductCount) {
NSLog(@"库房已满,请稍后加入商品");
[condition wait];//当前的线程会wait,singnal是单个唤醒,你无法确定是哪一个,系统还是说有序的
}
//生产商品,模拟生产商品的过程 0.2-2s的时间
[NSThread sleepForTimeInterval:0.2];//((arc4random() % 10) + 1) / 5.0];
//添加到库房中
[productsArray addObject:[[NSObject alloc] init]];
NSLog(@"%li", productsArray.count);
//发送一个通知给消费者,表示可以继续从库房取商品进行消费
[condition broadcast];//因为当前库房只能有一个行为在里面,全部唤醒
[condition unlock];
}
}
- (void)consumeProduct {
while (TRUE) {//一直循环
//其实也不是随机,计算机这么讲道理的
[condition lock];
//如果库房已空,一直等待
while (productsArray.count == 0) {
NSLog(@"库房已空,请稍等");
[condition wait];
}
//消费商品,模拟消费商品的过程 0.2-2s的时间
[NSThread sleepForTimeInterval:0.2];//((arc4random() % 10) + 1) / 5.0];
//从库房从取出商品
[productsArray removeLastObject];
NSLog(@"%li", productsArray.count);
//发送一个通知给生产者,表示可以继续向库房加入商品
[condition broadcast];
[condition unlock];
}
}
条件锁的死锁:条件锁的死锁产生的原因就是一个有两个对象互相锁住另外一个对象的进程
- (void)getChopsticksA {
@synchronized(zhangsan) {
NSLog(@"张三抢到了一根筷子,对李四说:小样儿,快把另一根给我");
[NSThread sleepForTimeInterval:1];
//@synchronized(lisi),死锁,因为首先是zhangsan锁住了,然后lisi也锁住了,只有等运行完了才解锁,因为几乎同时运行,lisizhangsan都锁住,他们进程运行下去都得靠对方,所以死锁,所以会有死锁,
{
NSLog(@"张三抢李四筷子");
}
}
}
- (void)getChopsticksB {
@synchronized(lisi) {
NSLog(@"李四抢到了一根筷子,对张三说:熊样儿,快把另一根给我");
@synchronized(zhangsan) {
NSLog(@"李四抢张三筷子");
}
}
}