一个NSThread对象就代表一条线程 下面是NSThread开启线程的方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self openThreadWithNSThread];
[NSThread mainThread];//获取主线程
[NSThread currentThread]; //获取当前线程
} - (void) openThreadWithNSThread {
/*
*第一个参数 目标对象 self
*第二个参数 方法选择器 调用的方法
*第三个参数 前面调用方法需要传递的参数 可以为nil
*/
//第一种方式
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:@"ABC"];
thread.name = @"线程1";
//0.0-1.0之间 1.0最高 0.0最低 默认0.5 越高线程被调用的频率越大
thread.threadPriority = 1.0;
[thread start];//需要手动调用启动线程
//第二种方式
[NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:@"abc2"];//自动启动线程 //第三种方式
[self performSelectorInBackground:@selector(threadAction:) withObject:@"开启一条后台线程"];//开启一条后台线程 //block方式
NSThread *thread1 = [[NSThread alloc] initWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
thread1.name = @"线程2";
thread1.threadPriority = 0.5;
[thread start]; //或者
[NSThread detachNewThreadWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}]; } - (void) threadAction:(NSString *)params {
NSLog(@"%@ and %@",params,[NSThread currentThread].name);
}

NSThread 创建线程的生命周期

当线程中的任务执行完毕后 线程被释放掉 可以继承NSThread创建一个新类 重写dealloc方法来验证

线程的状态

当线程处于就绪状态时线程会被移到可调度线程池里面(CPU只调度此线程池里面的线程),当处于阻塞状态时,线程会被移出可调度线程池,当处于死亡状态时 先移出线程池,再从内存中释放。

- (void)threadStatus {
//创建线程 在内存中创建一个线程 (新建状态)
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction1) object:nil];
[thread start]; //就绪状态 会被放倒可调度线程池里面 只有在可调度线程池里面的线程才是可以被CPU调度的 }
//一旦线程死亡了 就不能再次开启任务
- (void)threadAction1 {
//运行状态
for (NSInteger i = ; i < ; i ++) {
if (i == ) {
//[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
[NSThread sleepForTimeInterval:2.0];//阻塞状态 移出线程池
//两秒钟过后 再次进入就绪状态 等待调度进入运行状态
}
if (i == ) {
//break;//任务完成 自然死亡
[NSThread exit]; //废除线程强制进入死亡状态
}
NSLog(@"%@",[NSThread currentThread]);
}
//执行完方法之后死亡状态
}

线程的安全 也非常重要 这里介绍一种方法 后面会着重介绍

多线程的安全隐患

资源共享

1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象 同一个变量 同一个文件 此时就很容易引发数据错乱和数据安全问题.

安全隐患原因分析

安全隐患的解决

问题代码

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) NSThread *threadA;//售票员A
@property (nonatomic,strong) NSThread *threadB;//售票员B
@property (nonatomic,strong) NSThread *threadC;//售票员C
@property (nonatomic,assign) NSInteger totalCount; @end @implementation ViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//设置总票数
self.totalCount = ;
self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadA.name = @"售票员A";
[self.threadA start];
self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadB.name = @"售票员B";
[self.threadB start];
self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadC.name = @"售票员C";
[self.threadC start];
} //售票
- (void)saleTicket {
while () {
NSInteger count = self.totalCount;
if (count > ) {
for (NSInteger i = ; i < ; i ++) { }
//卖出去一张票
self.totalCount = count - ;
NSLog(@"%@ 卖出去一张票 还剩%zd张票",[NSThread currentThread].name,self.totalCount);
}else {
NSLog(@"票卖完了");
break;
}
} }

打印结果

-- ::38.600491+ NSThreadDemo[:] 售票员A 卖出去一张票  还剩999张票
-- ::38.600493+ NSThreadDemo[:] 售票员B 卖出去一张票 还剩999张票
-- ::38.600519+ NSThreadDemo[:] 售票员C 卖出去一张票 还剩999张票

问题解决代码

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) NSThread *threadA;//售票员A
@property (nonatomic,strong) NSThread *threadB;//售票员B
@property (nonatomic,strong) NSThread *threadC;//售票员C
@property (nonatomic,assign) NSInteger totalCount; @end @implementation ViewController - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//设置总票数
self.totalCount = ;
self.threadA = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadA.name = @"售票员A";
[self.threadA start];
self.threadB = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadB.name = @"售票员B";
[self.threadB start];
self.threadC = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.threadC.name = @"售票员C";
[self.threadC start];
} //售票
- (void)saleTicket {
while () {
//锁必须是全局唯一的
@synchronized(self) {
NSInteger count = self.totalCount;
if (count > ) {
for (NSInteger i = ; i < ; i ++) { }
//卖出去一张票
self.totalCount = count - ;
NSLog(@"%@ 卖出去一张票 还剩%zd张票",[NSThread currentThread].name,self.totalCount);
}else {
NSLog(@"票卖完了");
break;
}
}
} }

互斥锁的优缺点

优点:能有效防止因多线程抢夺资源造成的数据安全问题

缺点:需要消耗大量的CPU资源

互斥锁的使用前提:多条线程抢夺同一块资源

相关专业术语:线程同步,多条线程按顺序地执行任务

互斥锁,就是使用了线程同步技术

原子和非原子属性

OC在定义属性时有nonatomic和atomic两种选择

atomic:原子属性,为setter方法加锁(默认就是atomic)

nonatomic:非原子属性,不会为setter方法加锁

 @property (assign, atomic) int age;

 - (void)setAge:(int)age
{ @synchronized(self) {
_age = age;
}
}

原子和非原子属性的选择

nonatomic和atomic对比

atomic:线程安全,需要消耗大量的资源(并非是真正的线程安全 更准确的说应该是读写安全,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。)

nonatomic:非线程安全,适合内存小的移动设备

iOS开发的建议

所有属性都声明为nonatomic

尽量避免多线程抢夺同一块资源

尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

iOS 多线程之 NSThread的基本使用的更多相关文章

  1. iOS 多线程(NSThread、GCD、NSOperation)

    ios中得多线程技术主要使用3种:NSThread.NSOperation和GCD 一.NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期 NSThread的使用方法有2种 ...

  2. iOS多线程开发--NSThread NSOperation GCD

    多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势 ...

  3. IOS多线程(NSThread)

    1.创建方法 使用NSThread创建线程主要有两个个方法,分别如下 NSThread* myThread = [[NSThread alloc] initWithTarget:self   sele ...

  4. iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)

    2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然. ...

  5. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  6. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  7. iOS 多线程学习笔记 —— NSThread

    本文复制.参考自文章:iOS多线程编程之NSThread的使用  ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://blog.csdn.net/totogo ...

  8. [转]iOS多线程编程之NSThread的使用

    1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...

  9. iOS 多线程 简单学习NSThread NSOperation GCD

    1:首先简单介绍什么叫线程 可并发执行的,拥有最小系统资源,共享进程资源的基本调度单位. 共用堆,自有栈(官方资料说明iOS主线程栈大小为1M,其它线程为512K). 并发执行进度不可控,对非原子操作 ...

随机推荐

  1. LeetCode 格雷码序列的生成

    问题概述:在一组数的编码中,若随意两个相邻的代码仅仅有一位二进制数不同.则称这样的编码为格雷码. 2位数的格雷码序列:00 : 001 : 111 : 310 : 2找规律:假设要求n位的格雷码,先要 ...

  2. Node.js进阶篇-koa、钩子函数、websocket、嵌入式开发

    代码地址如下:http://www.demodashi.com/demo/12932.html 一.简介     koa是由Express原班人马打造的,致力于成为一个更小.更富有表现力.更健壮的We ...

  3. Tomcat 服务器只能存有一个正在运行的项目

    即使新建了一个new project (在同一个工作空间),启动Tomcat 还是会出现先前(工程名)一样的问题/异常. [原因]: 在底下Server 那里——Tomcat 7.X 底下会有很多工程 ...

  4. H5网站模板——前台和后台

    以下是比较典型的前台或者后台的H5模板: html5优分期大学生分期购物商城模板链接:http://pan.baidu.com/s/1dEUAzBz 密码:j150 红色的五金电气商城网站模板链接:h ...

  5. 【C语言天天练(二三)】errno变量

    引言: 在C编程中,errno是个必不可少的变量.特别是在网络编程中. 假设你没实用过errno,那仅仅能说明你的程序不够健壮. 为什么会使用errno呢?这是系统库设计中的一个无奈之举.他很多其它的 ...

  6. RandomForest 调参

    在scikit-learn中,RandomForest的分类器是RandomForestClassifier,回归器是RandomForestRegressor,需要调参的参数包括两部分,第一部分是B ...

  7. Shift Register(Using Submodule)

    /*************************************************** /  Shift Register module by Submodule /  Progra ...

  8. Creating Icon Overlay Handlers / 创建图标标记 Handlers (续) / VC++, Windows, DLL, ATL, COM

    创建图标标记 Handlers (续) 1.新建一个ATL Project. 2.建议将 Project Property 中 Linker – General - “Register Output” ...

  9. unity3d 导入google play services插件工程

    最近在给unity工程尝试接入google play services插件,遇到了些问题,记录一下. 之前在做android插件的时候,都是自己创建一个android工程,把生成的.class文件打包 ...

  10. socket demo程序

    package cn.example.socket; import java.io.BufferedReader; import java.io.IOException; import java.io ...