1.NSThread的基本使用
ZYXThread.h
#import
@interface ZYXThread : NSThread
@end
ZYXThread.m
#import "ZYXThread.h"
@implementation ZYXThread
- (void)dealloc
{
NSLog(@"ZYXThread -- dealloc");
}
@end
ViewController.h
#import
@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{
// 创建线程
//NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
// 启动线程
//[thread start];
//创建、启动线程 线程一启动,就会在线程thread中执行self的run方法
ZYXThread *thread = [[ZYXThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
thread.name = @"zyx-thread-1";//设置线程名字
[thread start];//启动线程
}
// run-----jack-----{number = 2, name = zyx-thread-1}
// run-----jack-----{number = 2, name = zyx-thread-1}
// run-----jack-----{number = 2, name = zyx-thread-1}
//2016-08-09 11:09:10.659 NSThread[25371:417117] ZYXThread -- dealloc
@end
一个NSThread对象就代表一条线程
- (void)run2:(NSString *)param{
NSLog(@"run2-----%@-----%@", param, [NSThread currentThread]);
}
- (void)createThread2{
//detach 分离
[ZYXThread detachNewThreadSelector:@selector(run2:) toTarget:self withObject:@"rose"];
}
// run2-----rose-----{number = 2, name = (null)}
// run2-----rose-----{number = 3, name = (null)}
// run2-----rose-----{number = 4, name = (null)}
// run2-----rose-----{number = 5, name = (null)}
// run2-----rose-----{number = 6, name = (null)}
// run2-----rose-----{number = 7, name = (null)}
// run2-----rose-----{number = 8, name = (null)}
// run2-----rose-----{number = 9, name = (null)}
// run2-----rose-----{number = 10, name = (null)}
// run2-----rose-----{number = 11, name = (null)}
// run2-----rose-----{number = 12, name = (null)}
// run2-----rose-----{number = 13, name = (null)}
执行完thread的任务并没有销毁这个thread
- (void)run3:(NSString *)param{
NSLog(@"run3-----%@-----%@", param, [NSThread currentThread]);
}
- (void)createThread3{
[self performSelectorInBackground:@selector(run3:) withObject:@"bill"];
}
// run3-----bill-----{number = 2, name = (null)}
// run3-----bill-----{number = 3, name = (null)}
// run3-----bill-----{number = 4, name = (null)}
// run3-----bill-----{number = 5, name = (null)}
// run3-----bill-----{number = 6, name = (null)}
// run3-----bill-----{number = 7, name = (null)}
// run3-----bill-----{number = 8, name = (null)}
// run3-----bill-----{number = 9, name = (null)}
// run3-----bill-----{number = 10, name = (null)}
// run3-----bill-----{number = 11, name = (null)}
// run3-----bill-----{number = 12, name = (null)}
// run3-----bill-----{number = 13, name = (null)}
// run3-----bill-----{number = 14, name = (null)}
// run3-----bill-----{number = 15, name = (null)}
// run3-----bill-----{number = 16, name = (null)}
// run3-----bill-----{number = 17, name = (null)}
执行完thread的任务并没有销毁这个thread
2.线程的状态
- (void)run{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"run-----%zd", i);
if (i == 4) {
[NSThread exit]; // 强制直接退出线程进入死亡状态(从内存中销毁)
}
}
}
- (void)createThread {
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
// run-----0
// run-----1
// run-----2
// run-----3
// run-----4
注意:一旦线程停止(死亡)了,就不能再次开启任务
- (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
线程进入阻塞状态(离开可调度线程池,线程没有销毁仍在内存中)
3.线程安全
@interface ViewController ()
/** 售票员01 */
@property (nonatomic, strong) ZYXThread *thread01;
/** 售票员02 */
@property (nonatomic, strong) ZYXThread *thread02;
/** 售票员03 */
@property (nonatomic, strong) ZYXThread *thread03;
/** 票的总数 */
@property (nonatomic, assign) NSInteger ticketCount;
@end
@implementation ViewController
- (void)saleTicket{
while (1) {
@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@" 线程 %@ 卖了一张票,还剩下%zd张", [ZYXThread currentThread].name, self.ticketCount);
} else {
NSLog(@" 线程 %@ 票已经卖完了",[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 票已经卖完了
// 线程 售票员03 票已经卖完了
// 线程 售票员01 票已经卖完了
@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
互斥锁保证线程安全
/** 锁对象 */
@property (nonatomic, strong) NSObject *locker;
- (void)start{
self.locker = [[NSObject alloc] init];
- (void)saleTicket{
while (1) {
//@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
@synchronized(self.locker){
// 线程 售票员01 卖了一张票,还剩下9张
// 线程 售票员02 卖了一张票,还剩下8张
// 线程 售票员03 卖了一张票,还剩下7张
// 线程 售票员01 卖了一张票,还剩下6张
// 线程 售票员02 卖了一张票,还剩下5张
// 线程 售票员03 卖了一张票,还剩下4张
// 线程 售票员01 卖了一张票,还剩下3张
// 线程 售票员02 卖了一张票,还剩下2张
// 线程 售票员03 卖了一张票,还剩下1张
// 线程 售票员01 卖了一张票,还剩下0张
// 线程 售票员02 票已经卖完了
// 线程 售票员03 票已经卖完了
// 线程 售票员01 票已经卖完了
使用同一把互斥锁 保证线程安全
- (void)saleTicket{
while (1) {
//@synchronized(self) { // 线程同步 互斥锁 锁对象必须唯一
//@synchronized(self.locker){
NSInteger count = self.ticketCount;
if (count > 0) {
self.ticketCount = count - 1;
NSLog(@" 线程 %@ 卖了一张票,还剩下%zd张", [ZYXThread currentThread].name, self.ticketCount);
} else {
NSLog(@" 线程 %@ 票已经卖完了",[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 票已经卖完了
// 线程 售票员03 票已经卖完了
// 线程 售票员01 票已经卖完了
不使用线程同步技术 不使用互斥锁 数据错乱
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]; // 根据图片的网络路径去下载图片数据
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();
(错误方式)在子线程显示图片
- (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];
}
子线程和主线程的数据通信:
子线程下载图片 把下载好的图片 传到主线程显示在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;
});
});
}