進程是系統資源管理的最小單位。線程是程序執行的最小單位。多線程是一個進程裡包含多個線程。一個進程數據會加載到一個內存區間中,其中的線程共享相同的內存空間。各個進程的地址是獨立的,只有進程能刷新UI、更新數據。線程需要手動開啟。
建立一個簡單售票系統,連接線程的運行。首先創建一個單視圖工程,在.h文件中代碼:
@interface LinViewController : UIViewController { //聲明剩余票數、賣出票數成員名 int _leftTickets; int _soldTickets; //聲明線程成員名 NSThread * _firstThread; NSThread * _secondThread; NSThread * _thridThread; //聲明線程鎖 NSCondition * _ticketsCondition; } //創建標簽欄的對象,用來顯示剩余票數、賣出票數、當前線程名 @property (retain, nonatomic) UILabel * leftLabel; @property (retain, nonatomic) UILabel * soldLabel; @property (retain, nonatomic) UILabel * currentThreadLabel; @end在.m文件中的代碼:
#import "LinViewController.h" //預編譯變量,設置票的總數量 #define MaxTickets 100 @implementation LinViewController //釋放創建的對象 - (void)dealloc { [_leftLabel release]; [_soldLabel release]; [_currentThreadLabel release]; [super dealloc]; } - (void)viewDidLoad { [super viewDidLoad]; //加載輔助的標簽欄,只顯示內容 [self addLabel:nil]; //設置標簽欄對象的位置 self.leftLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 90, 100, 30)]; self.soldLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 170, 100, 30)]; self.currentThreadLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 250, 100, 30)]; //設置標簽欄對象的背景顏色 self.leftLabel.backgroundColor = [UIColor lightGrayColor]; self.soldLabel.backgroundColor = [UIColor lightGrayColor]; self.currentThreadLabel.backgroundColor = [UIColor lightGrayColor]; //把標簽欄添加到當前的視圖中 [self.view addSubview:self.leftLabel]; [self.view addSubview:self.soldLabel]; [self.view addSubview:self.currentThreadLabel]; //初始化成員並賦值 _leftTickets = MaxTickets; _soldTickets = 0; _ticketsCondition = [[NSCondition alloc]init]; //創建按鈕對象 UIButton * pButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; //設置按鈕的位置 [pButton setFrame:CGRectMake(80, 340, 180, 40)]; //為按鈕添加標題 [pButton setTitle:@"開始賣票" forState:UIControlStateNormal]; //設置按鈕的方法,響應方式 [pButton addTarget:self action:@selector(threadStart:) forControlEvents:UIControlEventTouchUpInside]; //把按鈕添加到當前視圖中 [self.view addSubview:pButton]; } #pragma mark-------增加輔助標簽欄 - (void)addLabel:(id)sender { //初始化標簽欄對象對設置位置 UILabel * pLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 20, 300, 40)]; UILabel * pLabel1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 80, 120, 50)]; UILabel * pLabel2 = [[UILabel alloc]initWithFrame:CGRectMake(10, 160, 120, 50)]; UILabel * pLabel3 = [[UILabel alloc]initWithFrame:CGRectMake(10, 240, 120, 50)]; //設置標簽欄的內容文本 pLabel.text = @"模擬火車票銷售---多線程"; pLabel1.text = @"剩余票數"; pLabel2.text = @"售出票數"; pLabel3.text = @"當前進程"; //設置標簽欄的背景顏色 pLabel.backgroundColor = [UIColor clearColor]; pLabel1.backgroundColor = [UIColor clearColor]; pLabel2.backgroundColor = [UIColor clearColor]; pLabel3.backgroundColor = [UIColor clearColor]; //設置標簽欄的文本居中 pLabel.textAlignment = NSTextAlignmentCenter; pLabel1.textAlignment = NSTextAlignmentCenter; pLabel2.textAlignment = NSTextAlignmentCenter; pLabel3.textAlignment = NSTextAlignmentCenter; //把標簽欄對象添加到視圖中 [self.view addSubview:pLabel]; [self.view addSubview:pLabel1]; [self.view addSubview:pLabel2]; [self.view addSubview:pLabel3]; //釋放創建的對象 [pLabel release]; [pLabel1 release]; [pLabel2 release]; [pLabel3 release]; } #pragma mark-------開始賣票,線程開始運行 - (void)threadStart:(id)sender { //初始化子線程,設置子線程的方法 _firstThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil]; //設置子線程的名字 [_firstThread setName:@"thread-1"]; //??手動開啟子線程,必須添加,系統不能自主進行 [_firstThread start]; _secondThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil]; [_secondThread setName:@"thread-2"]; [_secondThread start]; _thridThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil]; [_thridThread setName:@"thread-3"]; [_thridThread start]; } //賣票的方法 - (void)sellTickets:(id)sender { while (YES) { //??鎖定線程,防止同一子線程多次運行,必須有 [_ticketsCondition lock]; //判斷票是否賣完 if (_leftTickets > 0) { //設置線程停止0.1秒 [NSThread sleepForTimeInterval:0.1]; //賣票的算法 _leftTickets--; _soldTickets = MaxTickets - _leftTickets; } else if (_leftTickets == 0) { NSLog(@"票已經賣完!"); break; } //子線程調用主線程更新視圖,只有進程能更新視圖 [self performSelectorOnMainThread:@selector(updateMyView:) withObject:[[NSThread currentThread]name] waitUntilDone:YES]; //輸出剩余票數、售出票數、當前線程,可以省略 NSLog(@"剩余票數:%i售出票數:%i當前線程%@",_leftTickets,_soldTickets,[[NSThread currentThread]name]); //線程解鎖 [_ticketsCondition unlock]; } } #pragma mark-------更新界面,進程可以,線程不可以 - (void)updateMyView:(id)sender { //設置標簽欄的顯示內容 self.leftLabel.text = [NSString stringWithFormat:@"%i",_leftTickets]; self.soldLabel.text = [NSString stringWithFormat:@"%i",_soldTickets]; self.currentThreadLabel.text = (NSString *)sender; //判斷是否賣完,若賣完則彈出警告框 if (_leftTickets == 0) { UIAlertView * pAlertView = [[UIAlertView alloc]initWithTitle:@"溫馨提示" message:@"票已經全部售出!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil]; [pAlertView show]; [pAlertView release]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end