多線程,java多線程

來源:互聯網
上載者:User

多線程,java多線程
一、iOS中多線程的實現方案

二、NSThread1. 建立和啟動線程

一個NSThread對象就代表一條線程

建立、啟動線程

 1 - (void)viewDidLoad { 2     [super viewDidLoad]; 3     // 建立並開啟一條子線程 4     NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"參數"]; 5     // 線程一啟動,就會線上程thread中執行self的run方法 6     [thread start]; 7 } 8 /** 9  *  開啟子線程10  *11  *  @param param object傳進來的參數12  */13 - (void)run:(NSString *)param14 {15     NSLog(@"currentThread:%@--run--%@", [NSThread currentThread], param);16 }17 18 列印結果:19 <NSThread: 0x7fd5b2f207f0>{number = 2, name = (null)}--run--參數

主線程相關用法

1 + (NSThread *)mainThread; // 獲得主線程2 - (BOOL)isMainThread; // 是否為主線程3 + (BOOL)isMainThread; // 是否為主線程

其他用法

獲得當前線程NSThread *current = [NSThread currentThread];線程的調度優先順序+ (double)threadPriority;+ (BOOL)setThreadPriority:(double)p;- (double)threadPriority;- (BOOL)setThreadPriority:(double)p;調度優先順序的取值範圍是0.0 ~ 1.0,預設0.5,值越大,優先順序越高線程的名字- (void)setName:(NSString *)n;- (NSString *)name;

其他建立線程方式

建立線程後自動啟動線程[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];隱式建立並啟動線程[self performSelectorInBackground:@selector(run) withObject:nil];

上述2種建立線程方式的優缺點

  • 優點:簡單快捷
  • 缺點:無法對線程進行更詳細的設定
2. 控制線程狀態
啟動線程- (void)start; // 進入就緒狀態 -> 運行狀態。當線程任務執行完畢,自動進入死亡狀態阻塞(暫停)線程+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 進入阻塞狀態強制停止線程+ (void)exit;// 進入死亡狀態

 注意:一旦線程停止(死亡)了,就不能再次開啟任務

3. 互斥鎖

互斥鎖使用格式:@synchronized(鎖對象) { // 需要鎖定的代碼  }

注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的

互斥鎖的優缺點

  • 優點:能有效防止因多線程搶奪資源造成的資料安全問題
  • 缺點:需要消耗大量的CPU資源 

互斥鎖的使用前提:多條線程搶奪同一塊資源

 

相關專業術語:線程同步

線程同步的意思是:多條線程按順序地執行任務

互斥鎖,就是使用了線程同步技術

4. 原子和非原子屬性

OC在定義屬性時有nonatomic和atomic兩種選擇

  • atomic:原子屬性,為setter方法加鎖(預設就是atomic)
  • nonatomic:非原子屬性,不會為setter方法加鎖

 atomic加鎖原理

1 @property (assign, atomic) int age;2 3 - (void)setAge:(int)age4 {5     @synchronized(self) {6         _age = age;7     }8 }

nonatomic和atomic對比

  • atomic:安全執行緒,需要消耗大量的資源
  • nonatomic:非安全執行緒,適合記憶體小的行動裝置
5. 線程間通訊

線程間通訊的體現

1個線程傳遞資料給另1個線程

在1個線程中執行完特定任務後,轉到另1個線程繼續執行任務

線程間通訊常用方法:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
三、GCD1. 簡介

全稱是Grand Central Dispatch,純C語言,提供了非常多強大的函數。

GCD的優勢

  • GCD是蘋果公司為多核的並行運算提出的解決方案
  • GCD會自動利用更多的CPU核心(比如雙核、四核)
  • GCD會自動管理線程的生命週期(建立線程、調度任務、銷毀線程)
  • 程式員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼
2. 任務和隊列

GCD中有2個核心概念

  • 任務:執行什麼操作
  • 隊列:用來存放任務

將任務添加到隊列中:

  • GCD會自動將隊列中的任務取出,放到對應的線程中執行
  • 任務的取出遵循隊列的FIFO原則:先進先出,後進後出
3. 執行任務

GCD中有2個用來執行任務的函數

  • 用同步的方式執行任務,queue:隊列  block:任務
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
  • 用非同步方式執行任務
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

同步和非同步區別

  • 同步:在當前線程中執行
  • 非同步:在另一條線程中執行
4. 隊列的類型

GCD的隊列可以分為2大類型

  • 並發隊列(Concurrent Dispatch Queue):可以讓多個任務並發(同時)執行(自動開啟多個線程同時執行任務),並發功能只有在非同步(dispatch_async)函數下才有效
  • 串列隊列(Serial Dispatch Queue):讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)
5. 並發隊列

GCD預設已經提供了全域的並發隊列,供整個應用使用,不需要手動建立

使用dispatch_get_global_queue函數獲得全域的並發隊列

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, // 隊列的優先順序unsigned long flags); // 此參數暫時無用,用0即可dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全域並發隊列

全域並發隊列的優先順序

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 預設(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 後台
6. 串列隊列

GCD中獲得串列有2種途徑

使用dispatch_queue_create函數建立串列隊列

dispatch_queue_tdispatch_queue_create(const char *label, // 隊列名稱 dispatch_queue_attr_t attr); // 隊列屬性,一般用NULL即可dispatch_queue_t queue = dispatch_queue_create("queue", NULL); // 建立dispatch_release(queue); // 非ARC需要釋放手動建立的隊列

使用主隊列(跟主線程相關聯的隊列)

主隊列是GCD內建的一種特殊的串列隊列

放在主隊列中的任務,都會放到主線程中執行

使用dispatch_get_main_queue()獲得主隊列

dispatch_queue_t queue = dispatch_get_main_queue();
7. 各種隊列的執行效果

8. 線程間通訊樣本

從子線程回到主線程

1 dispatch_async(2 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{3     // 執行耗時的非同步作業...4       dispatch_async(dispatch_get_main_queue(), ^{5         // 回到主線程,執行UI重新整理操作6         });7 });
9. 延時執行

iOS常見的延時執行有2種方式

  • 調用NSObject的方法

 

[self performSelector:@selector(run) withObject:nil afterDelay:2.0];// 2秒後再調用self的run方法

 

  • 使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{    // 2秒後非同步執行這裡的代碼...});
10. 一次性代碼

使用dispatch_once函數能保證某段代碼在程式運行過程中只被執行1次

1 static dispatch_once_t onceToken;2 dispatch_once(&onceToken, ^{3     // 只執行1次的代碼(這裡面預設是安全執行緒的)4 });
11. 隊列組

有這麼1種需求

首先:分別非同步執行2個耗時的操作

其次:等2個非同步作業都執行完畢後,再回到主線程執行操作

 如果想要快速高效地實現上述需求,可以考慮用隊列組

 1 dispatch_group_t group =  dispatch_group_create(); 2 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3     // 執行1個耗時的非同步作業 4 }); 5 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 6     // 執行1個耗時的非同步作業 7 }); 8 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 9     // 等前面的非同步作業都執行完畢後,回到主線程...10 });
12. 單例模式

單例模式可以保證在程式運行過程,一個類只有一個執行個體,而且該執行個體易於供外界訪問。從而方便地控制了執行個體個數,並節約系統資源。

單例模式在ARC\MRC環境下的寫法有所不同,需要編寫2套不同的代碼

可以用宏判斷是否為ARC環境

#if __has_feature(objc_arc)// ARC#else// MRC#endif
  • 單例模式 - ARC

ARC中,單例模式的實現:

1. 在.m中保留一個全域的static的執行個體

static id _instance;

2. 重寫allocWithZone:方法,在這裡建立唯一的執行個體(注意安全執行緒)

 

1 + (id)allocWithZone:(struct _NSZone *)zone2 {3     @synchronized(self) {4         if (!_instance) {5             _instance = [super allocWithZone:zone];6         }7     }8     return _instance;9 }

3. 提供1個類方法讓外界訪問唯一的執行個體

1 + (instancetype)sharedSoundTool2 {3     @synchronized(self) {4         if (!_instance) {5             _instance = [[self alloc] init];6         }7     }8     return _instance;9 }
  • 單例模式 – 非ARC

非ARC中(MRC),單例模式的實現(比ARC多了幾個步驟)

1. 實現copyWithZone:方法 

1 + (id)copyWithZone:(struct _NSZone *)zone2 {3     return _instance;4 }

2. 實現記憶體管理方法

1 - (id)retain { return self; }2 - (NSUInteger)retainCount { return 1; }3 - (oneway void)release {}4 - (id)autorelease { return self; }

 

四、NSOperation 

NSOperation的作用:

配合使用NSOperation和NSOperationQueue也能實現多線程編程

 

NSOperation和NSOperationQueue實現多線程的具體步驟:

  • 先將需要執行的操作封裝到一個NSOperation對象中
  • 然後將NSOperation對象添加到NSOperationQueue中
  • 系統會自動將NSOperation中封裝的操作放到一條新線程中執行
1. NSOperation的子類

NSOperation是個抽象類別,並不具備封裝操作的能力,必須使用它的子類

使用NSOperation子類的方式有3種

  • NSInvocationOperation
  • NSBlockOperation
  • 自訂子類繼承NSOperation,實現內部相應的方法

NSInvocationOperation

建立NSInvocationOperation對象

- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

調用start方法開始執行操作

- (void)start;

一旦執行操作,就會調用target的sel方法

注意:

  • 預設情況下,調用了start方法後並不會開一條新線程去執行操作,而是在當前線程同步執行操作
  • 只有將NSOperation放到一個NSOperationQueue中,才會非同步執行操作

NSBlockOperation

建立NSBlockOperation對象

+ (id)blockOperationWithBlock:(void (^)(void))block;

通過addExecutionBlock:方法添加更多的操作

- (void)addExecutionBlock:(void (^)(void))block;

注意:只要NSBlockOperation封裝的運算元 > 1,就會非同步執行操作

2. NSOperationQueue

NSOperationQueue的作用:NSOperation可以調用start方法來執行任務,但預設是同步執行的。如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統會自動非同步執行NSOperation中的操作。

添加操作到NSOperationQueue中

- (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block;
2.1 最大並發數

並發數也就是同時執行的任務數。比如,同時開3個線程執行3個任務,並發數就是3。

最大並發數的相關方法

- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
3. 隊列的取消、暫停、恢複

取消隊列的所有操作

- (void)cancelAllOperations;

也可以調用NSOperation的- (void)cancel方法取消單個操作

暫停和恢複隊列

- (void)setSuspended:(BOOL)b; // YES代表暫停隊列,NO代表恢複隊列- (BOOL)isSuspended;
4. 操作優先順序

設定NSOperation在queue中的優先順序,可以改變操作的執行順序

- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p;

優先順序的取值(優先順序越高,越先執行)

NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8
5. 操作依賴

NSOperation之間可以設定依賴來保證執行順序,比如一定要讓操作A執行完後,才能執行操作B,可以這麼寫:

[operationB addDependency:operationA]; // 操作B依賴於操作A

可以在不同queue的NSOperation之間建立依賴關係

注意:不能相互依賴,比如A依賴B,B依賴A

6. 操作的執行順序

對於添加到queue中的operations,它們的執行順序取決於2點:

  • 首先依據NSOperation之間的依賴關係
  • 然後依據NSOperation的優先順序

因此,總體的執行順序是:先滿足依賴關係,然後再從NSOperation中選擇優先順序最高的那個執行

7. 自訂NSOperation

自訂NSOperation的步驟很簡單

重寫- (void)main方法,在裡面實現想執行的任務

 

重寫- (void)main方法的注意點

  • 自己建立自動釋放池(因為如果是非同步作業,無法訪問主線程的自動釋放池)
  • 經常通過- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.