【原】iOS多线程之线程间通信和线程互斥
线程间通信
1> 线程间通信分为两种
主线程进入子线程(前面的方法都可以)
子线程回到主线程
2> 返回主线程
3> 代码
这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后在主线程刷新UI界面
视图布局我就不写了,大家自己来吧,线程间通信代码如下:
#pragma mark - 添加响应方法触发创建子线程并加载数据
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 创建子线程
[self performSelectorInBackground:@selector(loadImage) withObject:nil];
} - (void)loadImage
{
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
NSString *urlStr = @"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1463455875&di=ef2da3f0fe711b471966aa1511483d0b&src=http://img4.duitang.com/uploads/item/201308/20/20130820094450_rsmYi.jpeg"; NSURL *url = [NSURL URLWithString:urlStr]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; self.imageData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; // 返回主线程,刷新UI
[self performSelectorOnMainThread:@selector(reloadImageView) withObject:nil waitUntilDone:YES];
} - (void)reloadImageView
{
// 进入主线程一般进行来安全判断
if ([NSThread isMainThread]) {
// 刷新UI
UIImage *showIamge = [UIImage imageWithData:self.imageData]; self.showImageView.image = showIamge;
}
}
点击触发事件,开辟子线程成功,在主线程中刷新UI,图片显示成功
线程互斥
1> 应用场景
多线程并行编程中,线程间同步与互斥是一个很有技巧的也很容易出错的地方。
多个线程操作同一个资源(即某个对象),需要保证线程在对资源的状态(即对象的成员变量)进行一些非原子性操作后,状态仍然正确。
典型的例子是“售票厅售票应用”。售票厅剩余20张票,10个窗口去卖这些票。这10个窗口,就是10条线程,售票厅就是他们共同操作的资源,其中剩余的20张票就是这个资源的一个状态。线程买票的过程就是去递减这个剩余数量的过程。
我们看看会发生什么问题
- (void)viewDidLoad {
[super viewDidLoad];
// 模拟买票系统
// 一共20张票,10个窗口卖
__block NSInteger count = ;
dispatch_queue_t ticketQueue = dispatch_queue_create("sell ticket", DISPATCH_QUEUE_CONCURRENT);
for (int i = ; i < ; i ++) {
dispatch_async(ticketQueue, ^{
//这里相当于每个窗口卖2张票
for (int i = ; i < ; i ++) {
NSLog(@"买到了第%ld张票",count);
count--;
}
});
}
}
运行的效果如下图,不同的售票窗口贩卖了同一张
2> 线程互斥解决方案
- 方法一 @synchronized 自动对参数对象加锁,保证临界区内的代码线程安全(最简单的方法)
官方文档解释:
The @synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code.
个人理解:
@synchronized, 代表这个方法加锁, 相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程例如B正在用这个方法,有的话要等正在使用synchronized方法 的线程B运行完这个方法后再运行此线程A,没有的话,直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
@synchronized
方法控制对类(一般在IOS中用在单例中)的访问:每个类实例对应一把锁,每个 synchronized
方法都必须获得调用该方法锁方能执行,否则所属就会发生线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该
锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类,至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突(只要所有可能访问类的
方法均被声明为 synchronized)
- (void)viewDidLoad {
[super viewDidLoad];
// 模拟买票系统
// 一共20张票,10个窗口卖
__block NSInteger count = ;
__weak typeof(self) weakSelf = self;
dispatch_queue_t ticketQueue = dispatch_queue_create("sell ticket", DISPATCH_QUEUE_CONCURRENT);
for (int i = ; i < ; i ++) {
dispatch_async(ticketQueue, ^{
// 给买票操作加锁,保证代码块只有一个线程访问
@synchronized(weakSelf) {
//这里相当于每个窗口卖2张票
for (int i = ; i < ; i ++) {
NSLog(@"买到了第%ld张票",count);
count--;
}
}
});
}
}
运行结果:
- 方法二 NSLock
官方文档解释:
An NSLock object is used to coordinate the operation of multiple threads of execution within the same application. An NSLock object can be used to mediate access to an application’s global data or to protect a critical section of code, allowing it to run atomically.
个人理解:
在一个应用里面协调线程间的执行。
- (void)viewDidLoad {
[super viewDidLoad];
// 模拟买票系统
// 一共20张票,10个窗口卖
__block NSInteger count = ; // 创建线程锁
NSLock *lock = [[NSLock alloc]init];
dispatch_queue_t ticketQueue = dispatch_queue_create("sell ticket", DISPATCH_QUEUE_CONCURRENT);
for (int i = ; i < ; i ++) {
dispatch_async(ticketQueue, ^{
// 给买票操作加锁,保证代码块只有一个线程访问
// 加锁,不会出现多个窗口同时卖一张票的情况
[lock lock];
//这里相当于每个窗口卖2张票
for (int i = ; i < ; i ++) {
NSLog(@"买到了第%ld张票",count);
count--;
}
// 解锁
[lock unlock];
});
}
}
以上两种方法小编进行了使用,以下两种方法大家有兴趣可以试试,小编就不进行使用了
- 方法三 NSConditionLock 条件锁 可以设置条件
官方文档解释:
The NSConditionLock class defines objects whose locks can be associated with specific, user-defined conditions. Using an NSConditionLock object, you can ensure that a thread can acquire a lock only if a certain condition is met. Once it has acquired the lock and executed the critical section of code, the thread can relinquish the lock and set the associated condition to something new. The conditions themselves are arbitrary: you define them as needed for your application.
个人理解:
根据条件加锁与解锁。
- 方法四 NSRecursiveLock 递归锁 多次调用不会阻塞已获取该锁的线程
官方文档解释:
NSRecursiveLock defines a lock that may be acquired multiple times by the same thread without causing a deadlock, a situation where a thread is permanently blocked waiting for itself to relinquish a lock. While the locking thread has one or more locks, all other threads are prevented from accessing the code protected by the lock.
个人理解:
同一个线程可以多次请求加锁,但不会引起死锁。
【原】iOS多线程之线程间通信和线程互斥的更多相关文章
- 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)
注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好 ...
- Java 里如何实现线程间通信
正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点:thread.join(), object.w ...
- Java 如何实现线程间通信
正常情况下,每个子线程完成各自的任务就可以结束了.不过有的时候,我们希望多个线程协同工作来完成某个任务,这时就涉及到了线程间通信了. 本文涉及到的知识点: thread.join(), object. ...
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
- 06_Java多线程、线程间通信
1. 线程的概念 1.1多进程与多线程 进程:一个正在执行的程序.每个进程执行都有一个执行顺序,该顺序是一个执行路径,或叫一个控制单元. 一个进程至少有一个线程. 线程:就是进程中的一个独立 ...
- C++多线程编程(三)线程间通信
多线程编程之三——线程间通讯 作者:韩耀旭 原文地址:http://www.vckbase.com/document/viewdoc/?id=1707 七.线程间通讯 一般而言,应用程序中的一个次要线 ...
- Java多线程基础——线程间通信
在使用多线程的时候,经常需要多个线程进行协作来完成一件事情.在前面两章分析了Java多线程的基本使用以及利用synchronized来实现多个线程同步调用方法或者执行代码块.但上面两章的内容涉及到的例 ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- Java多线程:线程间通信之volatile与sychronized
由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信. Java为线程间通信提供了三个相关的关键字volatile, synchronized ...
随机推荐
- 关于快捷键 Ctrl+Alt+[方向键] 的知识
在用PS作图时使用 Ctrl+Alt+[方向键] 组合建时屏幕莫名翻转, 平时电脑懒得维护所以略卡,我不会说一般早上起床摁了开机去上完厕所回来还--咳咳 刚按下时瞬间一黑,再黑,,继续黑--真是大吃 ...
- 四、优化及调试--网站优化--Yahoo军规中
8.避免使用CSS表达式(避免在CSS中使用Expressions) 什么是CSS表达式:是用来把CSS属性和JavaScript关联起来.
- 三、jQuery--jQuery基础--jQuery基础课程--第3章 jQuery过滤性选择器
1.:first过滤选择器 本章我们介绍过滤选择器,该类型的选择器是根据某过滤规则进行元素的匹配,书写时以“:”号开头,通常用于查找集合元素中的某一位置的单个元素. 在jQuery中,如果想得到一组相 ...
- Android touch事件的派发流程
Android TouchEvent事件传递机制 通俗易懂,能够了解Touch事件派发的基本流程. Android中的dispatchTouchEvent().onInterceptTouchEven ...
- route 一个很奇怪的现象:我的主机能ping通同一网段的其它主机,并也能xshell 远程其它的主机,而其它的主机不能ping通我的ip,也不能远程我和主机
一个很奇怪的现象:我的主机能ping通同一网段的其它主机,并也能xshell 远程其它的主机,而其它的主机不能ping通我的ip,也不能远程我和主机. [root@NB Desktop]# route ...
- Matlab tips and tricks
matlab tips and tricks and ... page overview: I created this page as a vectorization helper but it g ...
- Java学习随笔5:Java多线程编程
1. 线程是程序中单独顺序的控制流,线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境. 2. 进程是执行中的程序,一个进程可以包含一个或多个线程,但至少要包含一个线程 ...
- Unity2D 之 Sprite点击事件
以下方法纯属我YY,切勿当真!!! 给 Sprite添加点击事件步骤: 1. 创建一个 Sprite 2. 给Sprite添加一个 Box Collider 2D 3. 将如果脚本放到Sprite上: ...
- document.body.scrollTop
标准浏览器:document.documentElement.scrollTop; 谷歌浏览器:document.body.scrollTop; var scrollTop = document.do ...
- java Iterator Fail-fast机制
Fail-fast:在迭代的过程中发现数据被改变时立即抛出异常,而不是等遍历完了再抛出异常:可以理解为快速感知. 在并发的时候,当线程A正遍历一个Collection或Map,这时另外一个线程B修改C ...