1.NSThread的基本使用
ZYXThread.h
#import <Foundation/Foundation.h>
@interface ZYXThread : NSThread
@end
ZYXThread.m
#import "ZYXThread.h"
@implementation ZYXThread
- (void)dealloc
{
NSLog(@"ZYXThread -- dealloc");
}
@end
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import "ZYXThread.h"
@implementation ViewController
- (void)run:(NSString *)param{
for (NSInteger i = 0; i<3; i++) {
NSLog(@"run-----%@-----%@", param, [NSThread currentThread]);
}
}
- (void)createThread1{
// 創(chuàng)建線程
//NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
// 啟動(dòng)線程
//[thread start];
//創(chuàng)建的妖、啟動(dòng)線程 線程一啟動(dòng),就會(huì)在線程thread中執(zhí)行self的run方法
ZYXThread *thread = [[ZYXThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
thread.name = @"zyx-thread-1";//設(shè)置線程名字
[thread start];//啟動(dòng)線程
}
// run-----jack-----<ZYXThread: 0x7fa7f951bf60>{number = 2, name = zyx-thread-1}
// run-----jack-----<ZYXThread: 0x7fa7f951bf60>{number = 2, name = zyx-thread-1}
// run-----jack-----<ZYXThread: 0x7fa7f951bf60>{number = 2, name = zyx-thread-1}
//2016-08-09 11:09:10.659 NSThread[25371:417117] ZYXThread -- dealloc
@end
一個(gè)NSThread對(duì)象就代表一條線程
- (void)run2:(NSString *)param{
NSLog(@"run2-----%@-----%@", param, [NSThread currentThread]);
}
- (void)createThread2{
//detach 分離
[ZYXThread detachNewThreadSelector:@selector(run2:) toTarget:self withObject:@"rose"];
}
// run2-----rose-----<NSThread: 0x7faae250e490>{number = 2, name = (null)}
// run2-----rose-----<NSThread: 0x7faae260cc50>{number = 3, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24a9d80>{number = 4, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251f410>{number = 5, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251f460>{number = 6, name = (null)}
// run2-----rose-----<NSThread: 0x7faae2511250>{number = 7, name = (null)}
// run2-----rose-----<NSThread: 0x7faae2511250>{number = 8, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24ab980>{number = 9, name = (null)}
// run2-----rose-----<NSThread: 0x7faae25112d0>{number = 10, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24b8e20>{number = 11, name = (null)}
// run2-----rose-----<NSThread: 0x7faae24b7c40>{number = 12, name = (null)}
// run2-----rose-----<NSThread: 0x7faae251a8f0>{number = 13, name = (null)}
執(zhí)行完thread的任務(wù)并沒(méi)有銷毀這個(gè)thread
- (void)run3:(NSString *)param{
NSLog(@"run3-----%@-----%@", param, [NSThread currentThread]);
}
- (void)createThread3{
[self performSelectorInBackground:@selector(run3:) withObject:@"bill"];
}
// run3-----bill-----<NSThread: 0x7fcd2bd1b920>{number = 2, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 3, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be0c9e0>{number = 4, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 5, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be0c9e0>{number = 6, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bc6fd90>{number = 7, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf0cba0>{number = 8, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 9, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf0cba0>{number = 10, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 11, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf037d0>{number = 12, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bd155f0>{number = 13, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2be15b30>{number = 14, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 15, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bf05e00>{number = 16, name = (null)}
// run3-----bill-----<NSThread: 0x7fcd2bc70320>{number = 17, name = (null)}
執(zhí)行完thread的任務(wù)并沒(méi)有銷毀這個(gè)thread
2.線程的狀態(tài)
- (void)run{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"run-----%zd", i);
if (i == 4) {
[NSThread exit]; // 強(qiáng)制直接退出線程進(jìn)入死亡狀態(tài)(從內(nèi)存中銷毀)
}
}
}
- (void)createThread {
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
// run-----0
// run-----1
// run-----2
// run-----3
// run-----4
注意:一旦線程停止(死亡)了孝宗,就不能再次開(kāi)啟任務(wù)
- (void)run2{
NSLog(@"%@",[NSDate date]);
// 阻塞(暫停)線程
[NSThread sleepForTimeInterval:2]; // 讓線程睡眠2秒(阻塞2秒)
NSLog(@"%@",[NSDate date]);
//[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
//[NSThread sleepUntilDate:[NSDate distantFuture]];
}
// 2016-08-09 05:36:01 +0000
// 2016-08-09 05:36:03 +0000
線程進(jìn)入阻塞狀態(tài)(離開(kāi)可調(diào)度線程池,線程沒(méi)有銷毀仍在內(nèi)存中)
3.線程安全
@interface ViewController ()
/** 售票員01 */
@property (nonatomic, strong) ZYXThread *thread01;
/** 售票員02 */
@property (nonatomic, strong) ZYXThread *thread02;
/** 售票員03 */
@property (nonatomic, strong) ZYXThread *thread03;
/** 票的總數(shù) */
@property (nonatomic, assign) NSInteger ticketCount;
@end
@implementation ViewController
- (void)saleTicket{
while (1) {
@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@" 線程 %@ 賣了一張票尉辑,還剩下%zd張", [ZYXThread currentThread].name, self.ticketCount);
} else {
NSLog(@" 線程 %@ 票已經(jīng)賣完了",[ZYXThread currentThread].name);
break;
}
}
}
}
- (void)start{
self.ticketCount = 10;
self.thread01 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread01.name = @"售票員01";
self.thread02 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread02.name = @"售票員02";
self.thread03 = [[ZYXThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread03.name = @"售票員03";
[self.thread01 start];
[self.thread02 start];
[self.thread03 start];
}
@end
// 線程 售票員01 賣了一張票,還剩下9張
// 線程 售票員02 賣了一張票歹袁,還剩下8張
// 線程 售票員03 賣了一張票,還剩下7張
// 線程 售票員01 賣了一張票,還剩下6張
// 線程 售票員02 賣了一張票俗孝,還剩下5張
// 線程 售票員03 賣了一張票,還剩下4張
// 線程 售票員01 賣了一張票魄健,還剩下3張
// 線程 售票員02 賣了一張票赋铝,還剩下2張
// 線程 售票員03 賣了一張票,還剩下1張
// 線程 售票員01 賣了一張票沽瘦,還剩下0張
// 線程 售票員02 票已經(jīng)賣完了
// 線程 售票員03 票已經(jīng)賣完了
// 線程 售票員01 票已經(jīng)賣完了
@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
互斥鎖保證線程安全
/** 鎖對(duì)象 */
@property (nonatomic, strong) NSObject *locker;
- (void)start{
self.locker = [[NSObject alloc] init];
- (void)saleTicket{
while (1) {
//@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
@synchronized(self.locker){
// 線程 售票員01 賣了一張票革骨,還剩下9張
// 線程 售票員02 賣了一張票,還剩下8張
// 線程 售票員03 賣了一張票析恋,還剩下7張
// 線程 售票員01 賣了一張票良哲,還剩下6張
// 線程 售票員02 賣了一張票,還剩下5張
// 線程 售票員03 賣了一張票助隧,還剩下4張
// 線程 售票員01 賣了一張票筑凫,還剩下3張
// 線程 售票員02 賣了一張票,還剩下2張
// 線程 售票員03 賣了一張票并村,還剩下1張
// 線程 售票員01 賣了一張票巍实,還剩下0張
// 線程 售票員02 票已經(jīng)賣完了
// 線程 售票員03 票已經(jīng)賣完了
// 線程 售票員01 票已經(jīng)賣完了
使用同一把互斥鎖 保證線程安全
- (void)saleTicket{
while (1) {
//@synchronized(self) { // 線程同步 互斥鎖 鎖對(duì)象必須唯一
//@synchronized(self.locker){
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@" 線程 %@ 賣了一張票,還剩下%zd張", [ZYXThread currentThread].name, self.ticketCount);
} else {
NSLog(@" 線程 %@ 票已經(jīng)賣完了",[ZYXThread currentThread].name);
break;
}
//}
}
}
// 線程 售票員01 賣了一張票哩牍,還剩下8張
// 線程 售票員02 賣了一張票棚潦,還剩下8張
// 線程 售票員03 賣了一張票,還剩下7張
// 線程 售票員01 賣了一張票膝昆,還剩下6張
// 線程 售票員02 賣了一張票瓦盛,還剩下5張
// 線程 售票員03 賣了一張票洗显,還剩下4張
// 線程 售票員01 賣了一張票,還剩下3張
// 線程 售票員02 賣了一張票原环,還剩下2張
// 線程 售票員03 賣了一張票挠唆,還剩下1張
// 線程 售票員01 賣了一張票,還剩下0張
// 線程 售票員02 票已經(jīng)賣完了
// 線程 售票員03 票已經(jīng)賣完了
// 線程 售票員01 票已經(jīng)賣完了
不使用線程同步技術(shù) 不使用互斥鎖 數(shù)據(jù)錯(cuò)亂
4.線程間通信
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
- (void)download{
NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
NSURL *url = [NSURL URLWithString:imgUrlStr];
NSDate *begin = [NSDate date];
NSData *data = [NSData dataWithContentsOfURL:url]; // 根據(jù)圖片的網(wǎng)絡(luò)路徑去下載圖片數(shù)據(jù)
NSDate *end = [NSDate date];
NSLog(@"%f", [end timeIntervalSinceDate:begin]);
self.imageView.image = [UIImage imageWithData:data];
}
- (void)way{
[self performSelectorInBackground:@selector(download) withObject:nil];
}
// 3.728395
CFTimeInterval begin = CFAbsoluteTimeGetCurrent();
NSData *data = [NSData dataWithContentsOfURL:url];
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
(錯(cuò)誤方式)在子線程顯示圖片
- (void)download3{
NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
NSURL *url = [NSURL URLWithString:imgUrlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data]; // 生成圖片
// 回到主線程 顯示圖片
/*
[self.imageView performSelector:@selector(setImage:)
onThread:[NSThread mainThread]
withObject:image
waitUntilDone:NO];
[self.imageView performSelectorOnMainThread:@selector(setImage:)
withObject:image
waitUntilDone:NO];
*/
[self performSelectorOnMainThread:@selector(showImage:)
withObject:image
waitUntilDone:YES];
}
- (void)showImage:(UIImage *)image{
self.imageView.image = image;
}
- (void)way3{
[self performSelectorInBackground:@selector(download3) withObject:nil];
}
子線程和主線程的數(shù)據(jù)通信:
子線程下載圖片 把下載好的圖片 傳到主線程顯示在imageView上
另外一種線程之間的通信方式
NSPort
NSMessagePort
NSMachPort
5.GCD線程間通信
- (void)loadImage {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *imgUrlStr = @"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg";
NSURL *url = [NSURL URLWithString:imgUrlStr];
NSData *data = [NSData dataWithContentsOfURL:url]; // 加載圖片
UIImage *image = [UIImage imageWithData:data]; // 生成圖片
// 回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
}