##程式 執行緒 ##
-
程式佔據記憶體,而執行緒佔據CPU。一個程式可以有多個執行緒,程式之間可以通過管道 或者套接字(Socket)進行通訊,而在一個程式中,多個執行緒相互之間可以直接 很方便的進行通訊。使用多執行緒程式設計可以幫助我們的程式減少 程式出現卡頓 假死這些情況的出現(不阻塞主執行緒的執行),使用起來可以極大的提升程式的使用者體驗,但是多執行緒也有一個不好的地方在於,你執行緒開得多了,對於其他程式來說就是一個不好的事情,其他程式佔用的資源就會變少。所以我們在使用多執行緒程式設計程式設計的時候要注意這點問題。
-
下面是一個使用多執行緒中NSOperation 的一個例子:
兩個按鈕模擬多執行緒 一個按鈕點選以後會睡眠10秒鐘 再執行的響應的內容 另外一個按鈕點選以後就會執行相應的內容 但是不適用多執行緒程式設計的時候 你點選了有睡眠的按鈕 第二個就不能點選了 因為第二個要等待第一個按鈕完成它的全部事件以後才會執行 這樣就造成了程式了卡頓 或者假死 所以這也是其我們要使用多執行緒程式設計的原因。
##程式碼區##
#import<UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
複製程式碼
#import<UIKit/UIKit.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void) foo:(UIButton *) button {
// 休眠和退出都是隻有正在執行的執行緒可以呼叫的方法
// 因此在設計上這兩個方法都是類方法而不是物件方法
// [NSThread exit];
// [NSThread sleepForTimeInterval:10]; 的作用和sleep(10)是一樣的
sleep(10);
NSLog(@"任務1已經完成!");
// 提示: 重新整理介面的操作要回到主執行緒處理否則有可能失效
// [self performSelectorOnMainThread:@selector(bar:) withObject:button waitUntilDone:YES];
// 建立一個操作物件
NSOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(bar:) object:button];
// 向主執行緒佇列中新增操作物件(操作放到主執行緒中執行)
[[NSOperationQueue mainQueue] addOperation:op];
}
//重新整理介面以後 讓按鈕又可以再點選 讓按鈕的文字恢復
- (void) bar:(UIButton *) button {
button.enabled = YES;
[button setTitle:@"任務1" forState:UIControlStateNormal];
}
- (IBAction)blueButtonClicked:(UIButton *)sender {
// 提示: 對於那些耗時間的任務基本上都應該放到其他的執行執行緒中
// 不要阻塞主執行緒的執行 否則介面會出現卡頓或假死現象
// 模擬任務需要執行10秒鐘
[sender setTitle:@"正在執行..." forState:UIControlStateNormal];
sender.enabled = NO;
// 建立一個操作物件(待會要將該操作放到一個佇列中去執行)
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self foo:sender];
}];
// 建立一個併發佇列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 設定最大併發數量
queue.maxConcurrentOperationCount = 5;
// 向佇列中新增一個操作
[queue addOperation:op];
// [NSThread detachNewThreadSelector:@selector(foo:) toTarget:self withObject:sender];
// NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(foo:) object:sender];
// 啟動執行緒(執行foo回撥方法)
// [thread start];
// sleep(1);
// 提示: 如果執行緒已經開始執行則無法取消 --->如果不執行前面的那個sleep(1) 執行緒可以被取消但是 執行了sleep(1)以後執行緒就無法被取消了。
// [thread cancel];
// [self performSelectorInBackground:@selector(foo:) withObject:sender];
}
- (IBAction)yellowButtonClicked:(UIButton *)sender {
NSLog(@"任務2已經完成!");
}
@end
複製程式碼
補充說明: 補充一點: 如果我們的程式中 出現了多個執行緒競爭同一個資源的情況,這個時候 我們需要對這個資源進行同步保護(synchronized) 讓執行緒處於一個排隊狀態 ,當一個執行緒進入執行的時候,鎖被鎖上,然後其他程式無法進入。直到該執行緒完成了它的工作以後,它就會出來 然後鎖就會被開啟 然後其他執行緒就接著一個一個的執行。當然一個完成以後 另外一個進入的時候 並不是有順序排好隊的進入 就好比哪個運氣好 哪個就先進去。
- 舉例說明:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//建立一個可變字串作為多個執行緒共同競爭的一個資源
NSMutableString *mStr = [NSMutableString stringWithCapacity:10000];
//建立5個執行緒模擬競爭同一個資源
for(int i = 0;i < 5; i++){
[NSThread detachNewThreadSelector:@selector(foo:) toTarget:self withObject:mStr];
}
return YES;
}
-(void)foo:(NSMutableString *)mStr{
for(int i = 0; i < 10000;i++){
@synchronized(mStr){
[mStr appendString:@"a"];
}
}
}
複製程式碼