線程的創(chuàng)建和開啟
一個NSThread對象就是一個線程
// 創(chuàng)建線程兼蜈,可以對線程對象進(jìn)行操作斜友,可以進(jìn)行詳細(xì)的設(shè)置
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"take"];
// 開啟線程洽故,當(dāng)線程執(zhí)行完畢袱耽,自動進(jìn)入死亡狀態(tài)
[thread start];
// 創(chuàng)建并開啟線程庄新,不能對線程進(jìn)行詳細(xì)的設(shè)置
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"me"];
// 在后臺運行广恢,即隱式創(chuàng)建并開啟線程,不能對線程進(jìn)行詳細(xì)的設(shè)置
[self performSelectorInBackground:@selector(run:) withObject:@"hand"];
// 線程已啟動馋没,就會執(zhí)行self中的run方法昔逗,Object后面的參數(shù)是傳給run方法的參數(shù)值
-(void)run:(NSString*)string {
for (int i=0; i<10000; i++) {
NSLog(@" -- run -- %@ -- %zd -- %@",string,i,[NSThread currentThread]);
}
}
// 線程的相關(guān)用法
// 獲得當(dāng)前線程
@property (class, readonly, strong) NSThread *currentThread;
// 線程的名字
@property (nullable, copy) NSString *name;
// 判斷是否是主線程
@property (readonly) BOOL isMainThread;
// 獲取主線程
@property (class, readonly, strong) NSThread *mainThread;
// 控制線程狀態(tài)
// 啟動線程,當(dāng)線程結(jié)束后篷朵,自動進(jìn)入死亡狀態(tài)
- (void)start;
// 取消線程
- (void)cancel;
// 阻塞(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 強制停止線程勾怒,進(jìn)入死亡狀態(tài)
+ (void)exit;
// 讓線程睡眠2秒(阻塞2秒)
[NSThread sleepForTimeInterval:2];
// 讓線程睡到遙遠(yuǎn)的未來,即永遠(yuǎn)的阻塞線程
[NSThread sleepUntilDate:[NSDate distantFuture]];
// 讓線程睡2秒
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
多線程的安全隱患
資源共享:一個資源被多個線程共享声旺,當(dāng)多個線程訪問一個資源時笔链,可能會引發(fā)數(shù)據(jù)錯亂和數(shù)據(jù)安全
image
image
互斥鎖
為了解決上面的安全隱患,需要給操作加互斥鎖
@synchronized (self) {
// 執(zhí)行的操作(需要鎖定的代碼)
}
// 注意腮猖,鎖定一份代碼秩序一把鎖鉴扫,用多個鎖是無效
互斥鎖的優(yōu)缺點:
- 優(yōu)點:能有效防止因為多線程搶奪資源造成的資源安全問題
- 缺點:需要消耗大量CPU資源
互斥鎖的使用前提:多條線程搶奪同一個資源
線程同步:多條線程在同一條線上執(zhí)行(按順序執(zhí)行任務(wù)) 〕喝保互斥鎖就是使用了線程同步技術(shù)
例子:
// 3個線程創(chuàng)建
self.thread01 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket:) object:@"sale"];
self.thread01.name = @"售票員01";
self.thread02 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket:) object:@"sale"];
self.thread02.name = @"售票員02";
self.thread03 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket:) object:@"sale"];
self.thread03.name = @"售票員03";
self.ticketCount = 100;
// 3個線程開啟
[self.thread01 start];
[self.thread02 start];
[self.thread03 start];
// 未加鎖
- (void)saleTicket:(NSString*)string {
while (1) {
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@"%@賣了一張幔妨,還剩下%zd張",[NSThread currentThread].name,self.ticketCount);
} else {
NSLog(@"全部賣完了");
break;
}
}
}
//**********log**************
售票員01賣了一張鹦赎,還剩下99張
售票員01賣了一張,還剩下97張
售票員02賣了一張误堡,還剩下98張
售票員01賣了一張古话,還剩下96張
售票員03賣了一張,還剩下95張
售票員02賣了一張锁施,還剩下93張
售票員01賣了一張陪踩,還剩下94張
售票員03賣了一張,還剩下92張
售票員02賣了一張悉抵,還剩下91張
售票員01賣了一張肩狂,還剩下90張
售票員03賣了一張,還剩下89張
售票員02賣了一張姥饰,還剩下88張
售票員01賣了一張傻谁,還剩下87張
售票員03賣了一張,還剩下86張
//***************************
// 加鎖
- (void)saleTicket:(NSString*)string {
while (1) {
@synchronized (self) {
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@"%@賣了一張列粪,還剩下%zd張",[NSThread currentThread].name,self.ticketCount);
} else {
NSLog(@"全部賣完了");
break;
}
}
}
}
//**********log**************
售票員01賣了一張审磁,還剩下99張
售票員01賣了一張,還剩下98張
售票員02賣了一張岂座,還剩下97張
售票員01賣了一張态蒂,還剩下96張
售票員03賣了一張,還剩下95張
售票員02賣了一張费什,還剩下94張
售票員01賣了一張钾恢,還剩下93張
售票員03賣了一張,還剩下92張
售票員02賣了一張鸳址,還剩下91張
售票員01賣了一張瘩蚪,還剩下90張
售票員03賣了一張,還剩下89張
售票員02賣了一張稿黍,還剩下88張
售票員01賣了一張募舟,還剩下87張
售票員03賣了一張,還剩下86張
//***************************
線程之間的通信
體現(xiàn):一個線程給另一個線程傳遞數(shù)據(jù)闻察;在一個線程中執(zhí)行完特定任務(wù)后,裝到另一個線程繼續(xù)執(zhí)行任務(wù)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesBegan -- ");
// 開啟子線程
[NSThread detachNewThreadSelector:@selector(upload) toTarget:self withObject:nil];
}
- (void)upload {
// 在子線程中執(zhí)行圖片數(shù)據(jù)請求(耗時操作)
NSString *urlStr = [NSString stringWithFormat:@"https://www.baidu.com/img/bd_logo1.png"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]];
UIImage *image = [UIImage imageWithData:data];
// 回到主線程 waitUntilDone:是否需要等待主線程完成后在進(jìn)行其他操作
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
// 回到主線程琢锋,在主線程執(zhí)行self.imageView的setImage操作辕漂,參數(shù)是image
// [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
// 回到主線程,在主線程執(zhí)行self.imageView的setImage操作吴超,參數(shù)是image
// [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
}
- (void)showImage:(UIImage*)image {
self.imageView.image = image;
}