進程 線程
進程占據(jù)內存,而線程占據(jù)CPU澎蛛。一個進程可以有多個線程责循,進程之間可以通過管道 或者套接字(Socket)進行通信阀捅,而在一個進程中拂铡,多個線程相互之間可以直接 很方便的進行通信陨溅。使用多線程編程可以幫助我們的程序減少 程序出現(xiàn)卡頓 假死這些情況的出現(xiàn)(不阻塞主線程的執(zhí)行)终惑,使用起來可以極大的提升程序的用戶體驗,但是多線程也有一個不好的地方在于门扇,你線程開得多了雹有,對于其他進程來說就是一個不好的事情,其他進程占用的資源就會變少臼寄。所以我們在使用多線程編程編程的時候要注意這點問題霸奕。
-
下面是一個使用多線程中NSOperation 的一個例子:
兩個按鈕模擬多線程 一個按鈕點擊以后會睡眠10秒鐘 再執(zhí)行的響應的內容 另外一個按鈕點擊以后就會執(zhí)行相應的內容 但是不適用多線程編程的時候 你點擊了有睡眠的按鈕 第二個就不能點擊了 因為第二個要等待第一個按鈕完成它的全部事件以后才會執(zhí)行 這樣就造成了程序了卡頓 或者假死 所以這也是其我們要使用多線程編程的原因。
代碼區(qū)##
#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 {
// 休眠和退出都是只有正在執(zhí)行的線程可以調用的方法
// 因此在設計上這兩個方法都是類方法而不是對象方法
// [NSThread exit];
// [NSThread sleepForTimeInterval:10]; 的作用和sleep(10)是一樣的
sleep(10);
NSLog(@"任務1已經(jīng)完成!");
// 提示: 刷新界面的操作要回到主線程處理否則有可能失效
// [self performSelectorOnMainThread:@selector(bar:) withObject:button waitUntilDone:YES];
// 創(chuàng)建一個操作對象
NSOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(bar:) object:button];
// 向主線程隊列中添加操作對象(操作放到主線程中執(zhí)行)
[[NSOperationQueue mainQueue] addOperation:op];
}
//刷新界面以后 讓按鈕又可以再點擊 讓按鈕的文字恢復
- (void) bar:(UIButton *) button {
button.enabled = YES;
[button setTitle:@"任務1" forState:UIControlStateNormal];
}
- (IBAction)blueButtonClicked:(UIButton *)sender {
// 提示: 對于那些耗時間的任務基本上都應該放到其他的執(zhí)行線程中
// 不要阻塞主線程的執(zhí)行 否則界面會出現(xiàn)卡頓或假死現(xiàn)象
// 模擬任務需要執(zhí)行10秒鐘
[sender setTitle:@"正在執(zhí)行..." forState:UIControlStateNormal];
sender.enabled = NO;
// 創(chuàng)建一個操作對象(待會要將該操作放到一個隊列中去執(zhí)行)
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{
[self foo:sender];
}];
// 創(chuàng)建一個并發(fā)隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 設置最大并發(fā)數(shù)量
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];
// 啟動線程(執(zhí)行foo回調方法)
// [thread start];
// sleep(1);
// 提示: 如果線程已經(jīng)開始執(zhí)行則無法取消 --->如果不執(zhí)行前面的那個sleep(1) 線程可以被取消但是 執(zhí)行了sleep(1)以后線程就無法被取消了吉拳。
// [thread cancel];
// [self performSelectorInBackground:@selector(foo:) withObject:sender];
}
- (IBAction)yellowButtonClicked:(UIButton *)sender {
NSLog(@"任務2已經(jīng)完成!");
}
@end
補充說明:
補充一點: 如果我們的程序中 出現(xiàn)了多個線程競爭同一個資源的情況质帅,這個時候 我們需要對這個資源進行同步保護(synchronized) 讓線程處于一個排隊狀態(tài) ,當一個線程進入執(zhí)行的時候,鎖被鎖上临梗,然后其他進程無法進入涡扼。直到該線程完成了它的工作以后,它就會出來 然后鎖就會被打開 然后其他線程就接著一個一個的執(zhí)行盟庞。當然一個完成以后 另外一個進入的時候 并不是有順序排好隊的進入 就好比哪個運氣好 哪個就先進去吃沪。
- 舉例說明:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//創(chuàng)建一個可變字符串作為多個線程共同競爭的一個資源
NSMutableString *mStr = [NSMutableString stringWithCapacity:10000];
//創(chuàng)建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"];
}
}
}