longOperation:- (void)longOperation:(id)obj {
    NSLog(@"%@ - %@", [NSThread currentThread], obj);
}- (void)threadDemo1 {
    NSLog(@"before %@", [NSThread currentThread]);
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(longOperation:) object:@"THREAD"];
    [thread start];
    NSLog(@"after %@", [NSThread currentThread]);
}[thread start];执行后,会在另外一个线程执行 longOperation: 方法block除外)- (void)threadDemo2 {
    NSLog(@"before %@", [NSThread currentThread]);
    [NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self withObject:@"DETACH"];
    NSLog(@"after %@", [NSThread currentThread]);
}detachNewThreadSelector 类方法不需要启动,会自动创建线程并执行 @selector 方法- (void)threadDemo3 {
    NSLog(@"before %@", [NSThread currentThread]);
    [self performSelectorInBackground:@selector(longOperation:) withObject:@"PERFORM"];
    NSLog(@"after %@", [NSThread currentThread]);
}performSelectorInBackground 是 NSObject 的分类方法@selector 方法thread 字眼,隐式创建并启动线程NSObject 都可以使用此方法,在其他线程执行方法NSThread 的实例化方法中的 target 指的是开启线程后,在线程中执行 哪一个对象 的 @selector 方法@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
+ (instancetype)personWithDict:(NSDictionary *)dict {
    id obj = [[self alloc] init];
    [obj setValuesForKeysWithDictionary:dict];
    return obj;
}
- (void)longOperation:(id)obj {
    NSLog(@"%@ - %@ - %@", [NSThread currentThread], self.name, obj);
}
@end@property (nonatomic, strong) Person *person;- (Person *)person {
    if (_person == nil) {
        _person = [Person personWithDict:@{@"name": @"zhangsan"}];
    }
    return _person;
}NSThread *thread = [[NSThread alloc] initWithTarget:self.person selector:@selector(longOperation:) object:@"THREAD"];
[thread start];[NSThread detachNewThreadSelector:@selector(longOperation:) toTarget:self.person withObject:@"DETACH"];[self.person performSelectorInBackground:@selector(longOperation:) withObject:@"PERFORM"];target 会在后台线程执行该对象的 @selector 方法target 就写 selfperformSelectorInBackground 可以让方便地在后台线程执行任意 NSObject 对象的方法新建 就绪 start 消息,线程对象被加入 可调度线程池 等待 CPU 调度detach 方法和 performSelectorInBackground 方法会直接实例化一个线程对象并加入 可调度线程池运行 可调度线程池中线程的执行就绪和运行之间来回切换就绪和运行之间的状态变化由 CPU 负责,程序员不能干预阻塞 sleepForTimeInterval:休眠指定时长sleepUntilDate:休眠到指定日期@synchronized(self):乎斥锁死亡 - (void)statusDemo {
    NSLog(@"先睡会");
    [NSThread sleepForTimeInterval:1.0];
    for (int i = 0; i < 20; i++) {
        if (i == 9) {
            NSLog(@"再睡会");
            [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
        }
        NSLog(@"%d %@", i, [NSThread currentThread]);
        if (i == 16) {
            NSLog(@"88");
            // 终止线程之前,需要记住释放资源
            [NSThread exit];
        }
    }
    NSLog(@"over");
}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // 注意不要在主线程上调用 exit 方法
//    [NSThread exit];
    // 实例化线程对象(新建)
    NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(statusDemo) object:nil];
    // 线程就绪(被添加到可调度线程池中)
    [t start];
}方法执行过程,符合某一条件时,可以利用 sleep 方法让线程进入 阻塞 状态
sleepForTimeInterval 从现在起睡多少秒sleepUntilDate 从现在起睡到指定的日期[NSThread exit];注意:线程从
就绪和运行状态之间的切换是由CPU负责的,程序员无法干预
// MARK: - 线程属性
- (void)threadProperty {
    NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    // 1. 线程名称
    t1.name = @"Thread AAA";
    // 2. 优先级
    t1.threadPriority = 0;
    [t1 start];
    NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
    // 1. 线程名称
    t2.name = @"Thread BBB";
    // 2. 优先级
    t2.threadPriority = 1;
    [t2 start];
}
- (void)demo {
    for (int i = 0; i < 10; ++i) {
        // 堆栈大小
        NSLog(@"%@ 堆栈大小:%tuK", [NSThread currentThread], [NSThread currentThread].stackSize / 1024);
    }
    // 模拟崩溃
    // 判断是否是主线程
//    if (![NSThread currentThread].isMainThread) {
//        NSMutableArray *a = [NSMutableArray array];
//
//        [a addObject:nil];
//    }
}name - 线程名称threadPriority - 线程优先级0~1.0 1.0表示优先级最高0.0表示优先级最低0.5stackSize - 栈区大小512K[NSThread currentThread].stackSize = 1024 * 1024;isMainThread - 是否主线程多线程开发的复杂度相对较高,在开发时可以按照以下套路编写代码:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    self.tickets = 20;
    [self saleTickets];
}
/// 卖票逻辑 - 每一个售票逻辑(窗口)应该把所有的票卖完
- (void)saleTickets {
    while (YES) {
        if (self.tickets > 0) {
            self.tickets--;
            NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);
        } else {
            NSLog(@"没票了 %@", [NSThread currentThread]);
            break;
        }
    }
}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    self.tickets = 20;
    NSThread *t1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
    t1.name = @"售票员 A";
    [t1 start];
    NSThread *t2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
    t2.name = @"售票员 B";
    [t2 start];
}- (void)saleTickets {
    while (YES) {
        // 模拟休眠
        [NSThread sleepForTimeInterval:1.0];
        if (self.tickets > 0) {
            self.tickets--;
            NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);
        } else {
            NSLog(@"没票了 %@", [NSThread currentThread]);
            break;
        }
    }
}运行测试结果
- (void)saleTickets {
    while (YES) {
        [NSThread sleepForTimeInterval:1.0];
        @synchronized(self) {
            if (self.tickets > 0) {
                self.tickets--;
                NSLog(@"剩余票数 %d %@", self.tickets, [NSThread currentThread]);
                continue;
            }
        }
        NSLog(@"没票了 %@", [NSThread currentThread]);
        break;
    }
}[[NSUserDefaults standardUserDefaults] synchronize];NSObject 对象self,这样可以避免单独再创建一个锁对象setter 方法),能够保证同一时间只有一个线程执行写入操作单(线程)写多(线程)读的多线程技术原子属性的效率比互斥锁高,不过可能会出现脏数据nonatomic@property (nonatomic, strong) NSObject *obj1;
@property (atomic, strong) NSObject *obj2;
@property (nonatomic, strong) NSObject *obj3;@synthesize obj3 = _obj3;
- (void)setObj3:(NSObject *)obj3 {
    @synchronized(self) {
        _obj3 = obj3;
    }
}
- (NSObject *)obj3 {
    return _obj3;
}
* 性能测试
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    int largeNumber = 1000 * 10000;
    NSLog(@"非原子属性");
    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < largeNumber; i++) {
        self.obj1 = [[NSObject alloc] init];
    }
    NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);
    NSLog(@"原子属性");
    start = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < largeNumber; i++) {
        self.obj2 = [[NSObject alloc] init];
    }
    NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);
    NSLog(@"模拟原子属性");
    start = CFAbsoluteTimeGetCurrent();
    for (int i = 0; i < largeNumber; i++) {
        self.obj3 = [[NSObject alloc] init];
    }
    NSLog(@"%f", CFAbsoluteTimeGetCurrent() - start);
}
原子属性内部的锁是
自旋锁,自旋锁的执行效率比互斥锁高
共同点
不同点
互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒自旋锁:如果发现有其他线程正在执行锁定的代码,线程会以死循环的方式,一直等待锁定代码执行完成结论
锁UIKit 不是线程安全的约定:所有更新 UI 的操作都必须主线程上执行!
主线程又被称为UI 线程nonatomic/// 根视图是滚动视图
@property (nonatomic, strong) UIScrollView *scrollView;
/// 图像视图
@property (nonatomic, weak) UIImageView *imageView;
/// 网络下载的图像
@property (nonatomic, weak) UIImage *image;Storyboard & XIB 是等价的如果重写了
loadView,Storyboard&XIB都无效
- (void)loadView {
    _scrollView = [[UIScrollView alloc] init];
    _scrollView.backgroundColor = [UIColor orangeColor];
    self.view = _scrollView;
    UIImageView *iv = [[UIImageView alloc] init];
    [self.view addSubview:iv];
    _imageView = iv;
}- (void)viewDidLoad {
    [super viewDidLoad];
    // 下载图像
    [self downloadImage];
}- (void)downloadImage {
    // 1. 网络图片资源路径
    NSURL *url = [NSURL URLWithString:@"http://c.hiphotos.baidu.com/image/pic/item/4afbfbedab64034f42b14da1aec379310a551d1c.jpg"];
    // 2. 从网络资源路径实例化二进制数据(网络访问)
    NSData *data = [NSData dataWithContentsOfURL:url];
    // 3. 将二进制数据转换成图像
    UIImage *image = [UIImage imageWithData:data];
    // 4. 设置图像
    self.image = image;
}- (void)setImage:(UIImage *)image {
    // 1. 设置图像视图的图像
    self.imageView.image = image;
    // 2. 按照图像大小设置图像视图的大小
    [self.imageView sizeToFit];
    // 3. 设置滚动视图的 contentSize
    self.scrollView.contentSize = image.size;
}1> 设置滚动视图缩放属性
// 1> 最小缩放比例
self.scrollView.minimumZoomScale = 0.5;
// 2> 最大缩放比例
self.scrollView.maximumZoomScale = 2.0;
// 3> 设置代理
self.scrollView.delegate = self;2> 实现代理方法 - 告诉滚动视图缩放哪一个视图
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return self.imageView;
}3> 跟踪 scrollView 缩放效果
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    NSLog(@"%@", NSStringFromCGAffineTransform(self.imageView.transform));
}[self performSelectorInBackground:@selector(downloadImage) withObject:nil];[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];原文:http://blog.csdn.net/jiahao8915/article/details/47689977