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