zoukankan      html  css  js  c++  java
  • (五十七)线程的资源共享、单例的实现

    【资源共享的问题】

    例如线程A与B均实现数字Num的加一操作,如果不加以限制,可能A和B先后拿到最初的Num,然后返回Num+1,无法实现Num+1之后再+1。

    【互斥锁】

    使用互斥锁(@synchronized)来解决,让线程A操作时锁住Num,不允许B的读写,直到A操作完并且写回后,再让B进行工作,再锁住Num,直到B操作完毕,再解开锁,类似于上厕所,在厕所内要锁门一样。

    使用@synchronized(self){......}包装在内的为互斥锁的作用范围,会严重降低效率。因此应尽可能的减小范围。不推荐使用。

    【原子锁】

    一般的成员变量都写为nonatomic,即为非原子锁,如果写为atomic就是原子锁,这样的变量只支持多读单写,原子锁限制了写入,对读取没有影响,原子锁的性能影响较小。

    【并发编程的主要目的】

    并发编程最主要的目的是提高性能,让更多的代码同时运行,提高整体性能。

    由于手机端一般不必解决资源抢夺问题,因此一般不会涉及到资源抢夺。

    Tip:线程的休眠方法:

    [NSThread sleepForTimeInterval:0.1f];

    Tip:注意多线程开发永远不要相信一次运行结果。

    【UI都在主线程的原因】

    出于性能考虑,UIKit中绝大多数的类都不是线程安全的,因此,官方要求更新UI的相关操作应该在主线程中执行。


    【单例设计模式】

    如UIApplication、音频播放可以保证音乐一直播放,不随着视图控制器的改变而受到影响。

    再如一些硬件资源,例如加速计、屏幕(UIScreen mainScreen),带有sharedXxx和mainXxx关键字的常常都是单例。

    单例在面试中可能会要求手写。

    单例的实现步骤:

    1.任何对象的alloc方法都会最终调用allocWithZone来实例化,因此重写allocWithZone来实现初始化结果的唯一性。

    2.在allocWihtZone方法中,利用dispatch_once保证调用父类实现初始化的代码只被执行一次,最后返回对象本身。

    为了保证单例不被销毁,使用一个静态指针,静态指针存放在堆中,直到应用程序终止后才会被销毁。

    // 在iOS中,所有对象的内存空间分配,最终都会调用allocWithZone方法
    // 制作单例,需要重写此方法
    + (id)allocWithZone:(struct _NSZone *)zone{
        
        static DemoObj *instance;
        
        // dispatch_once_t是线程安全的
        static dispatch_once_t onceToken;
        // dispatch_once宏可以保证快代码的指令只被执行一次
        dispatch_once(&onceToken, ^{
            // 只会被执行一次
            instance = [super allocWithZone:zone];
        });
        
        return instance;
        
    }

    3.写一个sharedXxx方法用于返回单例对象,由于alloc已经唯一,因此直接在shared方法中返回一个初始化的实例即可:

    + (instancetype)sharedDemoObj{
        
        return [[self alloc] init];
        
    }

    单例的缺点:单例对象一旦被创建,对象指针会存放在静态区,在堆中分配空间,会在应用程序终止后才会释放。

    另一种单例的实现:注意这样是不好的。

    static DemoObj2 *instance;
    
    @implementation DemoObj2
    
    + (instancetype)sharedDemoObj2{
        
        if (!instance) {
            instance = [[self alloc] init];
        }
        
        return instance;
        
    }
    
    @end

    如果仅仅是实现了sharedXxx方法,如果仍使用alloc init仍可以得到多个实例。

    如果有两个线程同时实例化,很可能创建出两个实例来(是线程不安全的)。


  • 相关阅读:
    golang书签
    linux每日知识整理
    leetcode动态规划笔记五---双序列型
    leetcode动态规划笔记三---单序列型
    leetcode动态规划笔记二---矩阵型DP
    leetcode动态规划笔记一---一维DP
    linux系统IO操作
    golang知识精要(二)
    ubuntu修改键盘键位映射
    Python 使用 cx_Oracle 第三方库连接操作Oracle数据库
  • 原文地址:https://www.cnblogs.com/aiwz/p/6154193.html
Copyright © 2011-2022 走看看