您的位置:首页 > 其它

多线程

2015-08-12 06:18 218 查看
线程是进程中的一条执行路径

开启线程需要占用一定的内存空间,(默认情况下主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。

什么是主线程

一个iOS程序运行后,默认会开启1条线程,称为“主线程”或“UI线程”

主线程的主要作用

显示刷新/刷新UI界面

处理UI事件(点击事件,滚动事件,拖拽事件)

子线程:后台线程,异步线程

不能把比较耗时的操作放到主线程中。耗时操作会卡住主线程,严重影响UI的流畅度

NSThread

一个NSThread对象就代表一个线程

0、创建线程

NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(download)object:nil];

download是一个示例方法。

target

The object to which the message specified by
selector
is sent.
selector

The selector for the message to send to
target
. This selector must take only one argument and must not have a return value.
argument


The single argument passed to the target. May be
nil
.

1、获取主线程与当前线程,判断主线程

NSLog(@"%@",[NSThread mainThread]);

Returns the
NSThread
object
representing the main thread.

NSLog(@"%@",[NSThread currentThread]);
Returns the thread object representing
the current thread of execution.

NSLog(@"%d",[NSThread isMainThread]);

Returns a Boolean value that indicates whether the current thread is the main thread.

NSLog(@"%d",[thread isMainThread]);

A Boolean value that indicates whether the receiver is the main thread. (read-only)

2、优先级,不常用,了解备用



3、线程的名字

@property (copy)
NSString *name

- (void)setName:(NSString *)name;

- (NSString *)name;

更改主线程的名字

NSThread *th = [NSThreadmainThread];

th.name =@"主线程";

Console输出的解释:

2015-08-12 09:32:03.618多线程[8751:2897356] <NSThread: 0x7fbf0a2082a0>{number = 1, name =主线程}

number,线程编号,name ,线程名字,主线程编号永远为1

- (void)setName:(NSString *)name;

- (NSString *)name;

4、创建线程的其他类方法
创建线程后自动启动线程

[NSThreaddetachNewThreadSelector:@selector(download:)toTarget:selfwithObject:@"http://a.jpg"];

隐式创建线程并启动

[selfperformSelectorInBackground:@selector(download:)withObject:nil];
这两种方法的优点,简单快捷,缺点,无法对线程做更详细的设置。

线程的状态
线程的状态,其实就是以前操作系统课本上提到的,就绪,运行,阻塞三种最简单的状态,前面多加个新建,后面多加个死亡。
1新建:

NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(download)object:nil];
2就绪:

[threadstart];



NSLog(@"-----begin");



[NSThread
sleepForTimeInterval:5];



NSLog(@"-----end");

控制线程状态:



线程应该没有死亡,只是不能再start了。

多线程的安全隐患

买票问题演示 核心代码

NSLog(@"bagin,%@",[NSThread currentThread].name);

int count = self.leftTicketCount;

if (count > 0) {



NSLog(@"middle,%@",[NSThread currentThread].name);

self.leftTicketCount = count -1;

NSLog(@"%@卖了一张牌,剩余%d张票",[NSThreadcurrentThread].name,self.leftTicketCount);



NSLog(@"end,%@",[NSThread currentThread].name);

}

解决 :Using the @synchronized Directive
互斥锁

互斥锁使用格式
@synchronized(锁对象){需要锁定的代码}

互斥锁,能防止因多线程抢夺资源造成的数据安全问题,但需要消耗大量的CPU资源

互斥锁的使用前提,多线程抢夺同一块资源,多线程执行同一份代码。

The
@synchronized
directive
is a convenient way to create mutex locks on the fly in Objective-C code.

you do not have to create the mutex or lock object directly. Instead, you simply use any Objective-C object as a lock token

The object passed to the
@synchronized
directive
is a unique identifier used to distinguish the protected block.

If you pass
the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section.

If you execute the preceding method in two different threads, passing a different object for the
anObj
parameter
on each thread, each would take its lock and continue processing without being blocked by the other.



线程同步:多条线程在同一条线上执行(按顺序第执行任务)

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

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

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

atomic:

原子操作(原子性是指事务的一个完整操作,操作成功就提交,反之就回滚. 原子操作就是指具有原子性的操作)在objective-c 属性设置里面 默认的就是atomic ,意思就是 setter /getter函数是一个原子操作,如果多线程同时调用setter时,不会出现某一个线程执行完setter所有语句之前,另一个线程就开始执行setter,相当于 函数头尾加了锁 .
这样的话 并发访问性能会比较低 .

原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断。在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"
原子操作",因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。但是,在对称多处理器(Symmetric
Multi-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。

原子操作,必须完整结束后,再被调用。

nonatomic:

非原子操作 一般不需要多线程支持的时候就用它,这样在 并发访问的时候效率会比较高 . 在objective-c里面通常对象类型都应该声明为非原子性的. iOS中程序启动的时候系统只会自动生成一个单一的主线程.程序在执行的时候一般情况下是在同一个线程里面对一个属性进行操作. 如果在程序中 我们确定某一个属性会在多线程中被使用,并且需要做数据同步,就必须设置成原子性的,但也可以设置成非原子性的,然后自己在程序中用加锁之类的来做数据同步.
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁,资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
因为都是nonatomic,刷新UI界面的代码,不要放在子线程中。

线程通信
1、1个线程传递数据给另一个线程
2、在1个线程中执行完特定任务后,转到另一个线程继续执行任务。
3、

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

[selfperformSelectorInBackground:@selector(download)withObject:nil];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: