1>什麼是線程與進程
什麼是進程
進程是指在系統中正在運行的一個應用程序
每個進程之間是獨立的,每個進程均運行在其專用且受保護的內存空間內
比如同時打開QQ xcode
系統就會分別啓動2個進程
什麼是線程
1個進程要想執行任務,必須得有線程(每1個進程至少要有1條線程)
線程是進程的基本執行單元,一個進程(程序)的所有任務都在線程中執行
比如使用酷狗播放音樂,使用迅雷下載電影,都需要在線程中執行
2>
線程的串行
如果要在1個線程中執行多個任務,那麼只能一個一個地按順序執行這些任務
也就是說,在同一時間內,1個線程只能執行1個任務
因此,也可以認爲線程是進程中的1條執行路徑
3>多線程
1個進程中可以開啓多條線程,每條線程可以並行(同時)執行不同的任務
多線程的原理
同一時間,CPU只能處理1條線程,只有1條線程在工作(執行)
多線程併發(同時)執行,其實是CPU快速地在多條線程之間調度(切換)
如果CPU調度線程的時間足夠快,就造成了多線程併發執行的假象
多線程的優缺點
優點
能適當提高程序的執行效率 能適當提高資源利用率(CPU,內存利用率)
缺點
開啓線程需要佔用一定的內存空間(默認情況下,主線程佔用1M,子線程佔用512KB),如果開啓大量的線程,會佔用大量的內存空間,降低程序的性能
線程越多,CPU在調度線程上的開銷就越大
程序設計更加複雜:比如線程之間的通信,多線程的數據共享
4>主線程 /****** 重要 *****/
主線程的主要作用
主線程:一個iOS程序運行後,默認會開啓1條線程,稱爲“主線程”或“UI線程”.
顯示\刷新UI界面
處理UI事件(比如點擊事件,滾動事件,拖拽事件等)
主線程的使用注意
不要將比較耗時的操作放到主線程
耗時操作會卡住主線程,嚴重影響UI的流暢度,給用戶一種“卡”的壞體驗
不要同時開啓太多的線程(1-3條即可,不要超過5條)
主線程:UI線程,顯示,刷新UI界面,處理UI控件的事件
子線程:後臺線程,異步線程
耗時操作的執行
將耗時操作放在子線程(後臺線程,非主線程,異步線程)
二:多線程的基本使用:
1.多線程的分類
iOS中多線程的實現方案
NSThread GCD NSOperation
NSThread
一個NSThread對象就代表一條線程
{
//創建線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
//需要執行的內容
…….
//啓動線程
[thread start];
}
2.其他創建子線程的方式
1> 創建子線程並自動啓動
[NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:nil];
2> 隱式創建子線程
[self performSelectorInBackground:@selector(download) withObject:nil];
[NSThread currentThread]獲取當前線程
[NSThread mainThread]獲取主線程
+ (BOOL)isMainThread;//判斷所在方法是否在主線程中
- (BOOL)isMainThread;//判斷某個線程是否爲主線程
3> 線程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
4> 控制線程的狀態
1.啓動線程
- (void)start;
2.阻塞(暫停)線程
+(void)sleepUntilDate:(NSDate *)date;
+(void)sleepForTimeInterval:(NSTimeInterval)ti; //阻塞當前的線程,一般不建議使用
//一旦定製好
延遲任務後
不會卡住當前線程,建議使用
[self
performSelector:@selector(download) withObject:nil
afterDelay:3.0f];
進入阻塞狀態
3.強制停止線程
+ (void)exit;
進入死亡狀態
例如:
- (void)threadCreate3
{
//隱式創建子線程
[self performSelectorInBackground:@selector(download:) withObject:@"隱式創建子線程調用的方法"];
{
//隱式創建子線程
[self performSelectorInBackground:@selector(download:) withObject:@"隱式創建子線程調用的方法"];
}
- (void)threadCreate2
{
//創建一個子線程 並且自動啓動
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://www.baidu.com/1.jpg"];
{
//創建一個子線程 並且自動啓動
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://www.baidu.com/1.jpg"];
}
- (void)download:(NSString
*)url
{
NSLog(@"%s thread=%@ url=%@",__func__,[NSThread currentThread],url);
{
NSLog(@"%s thread=%@ url=%@",__func__,[NSThread currentThread],url);
}
- (void)threadCreate1
{
//1.創建一個子線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"打印";
//2.啓動線程
[thread start];
{
//1.創建一個子線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"打印";
//2.啓動線程
[thread start];
}
2。
多線程的安全隱患
1>.資源共享
塊資源可能會被多個線程共享,也就是多個線程可能會訪問一塊資源
.當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題
2>安全隱患解決-互斥鎖(同步鎖)
1.互斥鎖使用模式
@synchronized(鎖對象) {
//需要鎖定的代碼,即引起安全隱患的地方
}
//注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
缺點:需要消耗大量的CPU資源
例如:
//賣票的方法
_thread3
= [[NSThread
alloc]
initWithTarget:self
selector:@selector(sellTicket)
object:nil];
_thread3.name =
@"3號窗口”; //此處若有多個窗口時會造成多個窗口請求同一張票而造成線程安全
- (void)sellTicket
{
{
while (1) {
//()裏的對象是鎖對象
可以是任意類型的對象
稱爲同步鎖 也叫
互斥鎖
@synchronized(self) {
if (_count<=0) {
NSLog(@"賣光");
return;
} else {
[NSThread sleepForTimeInterval:1];
_count -= 1;
NSLog(@"%@賣票 還剩%d張",[NSThread currentThread].name,_count);
}
@synchronized(self) {
if (_count<=0) {
NSLog(@"賣光");
return;
} else {
[NSThread sleepForTimeInterval:1];
_count -= 1;
NSLog(@"%@賣票 還剩%d張",[NSThread currentThread].name,_count);
}
}//解鎖
}
}
三:線程間的通信:/***** 重要 ****/
1.什麼叫做線程間通信
在1個進程中,線程往往不是孤立存在的,多個線程之間需要經常進行通信,即:
1個線程傳遞數據給另1個線程,
在1個線程中執行完特定任務後,轉到另1個線程繼續執行任務
線程間通信常用方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
例如: