zoukankan      html  css  js  c++  java
  • 多线程并发同步总结

    前段做Zookeeper的Client4Net,涉及多线程较多。完了对多线程同步做下总结。由于是简单的汇总,主要给自己复习用,代码就不贴出来了。

    1.锁

      Lock:

        这个大家都知道没什么可以说的,内部使用Monitor实现,等同于try { Monitor.Enter(obj,ref lockTaKen); }finally { Monitor.Exit(obj); } 。

        注意几点就好:

          Lock(this)锁定当前对象,不建议;

          Lock(type)锁定某类型,这个范围太大,不小心就是死锁;效率低,不建议;

          Lock(string)这个比较疯狂,鉴于string的特殊性,所有Equal的string都会被锁住;没特殊要求不要使用;

          Lock(obj): 推荐,声明 static volatile object作为LockToken;

      Monitor:  

        静态类,作用范围全局。需要显式的Enter/TryEnter和Exist。比较简单不要将值类型当作参数传入就好,否则装箱后就变成锁定不同的对象了。

        需要注意一点是Pulse/TryPulse和Wait相关的就绪(ready)队列等待(waiting)队列,关于这个MSDN解释的比较模糊(就绪队列:包含准备获取锁的线程;等待队列:包含等待对象状态更改通知的线程)。

        首先只有持有锁的线程才能调用Wait和Pulse,一旦Wait必须Pulse才能被唤醒,Wait后释放锁,并进入等待队列。最大的好处是Wait的线程一旦收到Pulse信号就会从等待队列中插队到就绪队列以使其能尽可能早的获取锁。最好使用其包含超时参数的重载,这样超时后会马上进入就绪队列并能根据其返回值决定是否再次Wait,也避免后续获取锁的线程在Pluse前Exit造成无限等待。

          

      Mutex:

        继承自WaitHandle, 静态方法全局可跨进程,实例化方法作用与当前域;

        主要API为继承自WaitHandle的WaitOne: 等待waitHandle信号。堵塞当前线程,超过预期等待时间后返回False。信号等同MenuResetHandle、AutoResetHandle可用于互操作。这个用起来太危险了,跨进程锁定没有特殊理由建议换个方式实现进程同步。碰到过一次,Trouble Shooting过程生不如死。不多说。最后重现将内存全转储到文件一点点找才发现。

      SpinLock: 自旋锁,这货是值类型,意味这更轻量级、更高效、大量使用也会更耗资源。(注意区分SpinWait)等待时通过自旋不退出CPU执行,不用切换效率高,粒度较细,如锁定时间较长将消耗CPU,非特殊原因不推荐使用。建议其他锁类型存在性能问题后再来试试这个。 

      ReadWriteLock/ReadWriteLockSlim: 读写锁,4.5推荐后者。读锁,写锁,可升级读锁;我写别人都不能读,任何人读时都不能写。类似与数据库的可重复读隔离级别。

        Semaphore: 继承者WaitHandle,信号量,创建指定资源数的锁,可用以实现类似池的结构。初始化时指定最大资源数,资源数为零是堵塞新的资源申请线程,等待占用资源线程推出占用。和CountDownEvent相反。主要API为WaitOne 继承自WaitHandle,进入,不必多说。注意这个继承自WaitHandle,类本身没有继承自WaitHandle,没看源码,应该内嵌WaitHandle实例。所以依然放Lock没有放到通知里。Release: 退出,-1/-N。

    2.通知 

      WaitHandle

        应该算同步信号量最重要的一个基类(抽象类),提供Wait虚方法接口供子类实现了。同时提供WaitAll,WaitAny,SignalAndWait的静态方法用以调度协调跨子类的信号量。

      Join : Thread方法,阻塞当前线程知道指定时间或某个线程终止。不用多说。

      EventWaitHandle : 另一个重量级的类,继承自WaitHandle,通过设置EventHandleMode枚举设置手动或自动释放, 更常使用子类AutoResetEvent,ManualResetEvent。

        主要API:

          SignalAndWait: 静态,根据属性EventHandleMode设置信号类型,AutoRest: 调用一次发出一个释放信号,使一个调用该类实例的Set方法阻塞的线程继续,然后信号重置。

          MenuRest:信号不会自动重置,调用后所有调用该类实例的Set方法阻塞的线程继续。

          Set : 将事件状态设置为终止状态,允许一个或多个等待线程继续。某线程:“我暂停了哈,可以走了通知我”。

          Reset : 将事件状态设置为非终止状态,导致线程阻止。handle广播:“你们可以走了”。(AutoRest:“走一个”;MenuRest:“都走吧”)。

          WaitOne: 等待指定时间获取信号量,没等到返回False继续;指定时间内收到信号继续。类似与:if(ewh.WaitOne(1000)){//超时前获得信号}else{//超时没获得信号}。

      AutoRestEvent/AutoRestEventSlim: 继承自EventWaitHandle,EventHandleMode = AutoRest的EventHandleMode。后者更轻量级,推荐后者。   

      MenualRestEvent/MenualRestEventSlim: 继承自EventWaitHandle,EventHandleMode = MenualRestEvent的EventHandleMode。后者更轻量级,推荐后者。

        Barrier: 屏障,可是线程分阶段执行,配合Parallel使用可以完成这用的功能:第一阶段:3个独立任务,都完成进入下已阶段;下一阶段可以是1个或多个任务并行。构造函数可为一个Int和一个Action的参数,当SinalandWait的次数达到Int参数值时执行Action。Like this:

        Barrier br = new(2,(b)=>{//do something;}); 
          Action a = ()=>{//do 1; br.SinalandWait(); //do 2; br.SinalandWait(); //do 3};
          Action b = ()=>{//do 1; br.SinalandWait(); //do 2; br.SinalandWait(); //do 3}; 
          Action c = ()=>{//do 1; br.SinalandWait(); //do 2; br.SinalandWait(); //do 3};  
          Action d = ()=>{//do 1; br.SinalandWait(); //do 2; br.SinalandWait(); //do 3};   
      Parallel.Invoke(a,b,c);
    //Parallel.Invoke(a,b,c,d)//will throw exception;

        主要API:

          AddParticipant/AddParticipants: 添加一个/多个参与者(任务执行者,Action),这个接口怪怪的。不理解参数都是Int为啥设计成这样。

          RemoveParticipant/RemoveParticipants :移除一个/多个参与者。

          SinalAndWait: 线程告诉Barrier:“我到了啊,等在等着呢,什么时候继续喊我,我还有其他事要接着干呢”,Barrier:“好,都到齐了我会喊你继续的。”。

      SpinWait: 轻量级信号量,通过自旋等待信号,不同退出CPU执行。

        主要API:

          Reset: 重载自旋计数器,重新开始计数。

          Spinone: 自旋一次,通常在循环里使用,自旋一次后检查条件是否满足。

          Count:已自旋次数。

          SpinUnit:最重要函数,包含一个Func参数和一个时间,自旋一次后执行返回Func结果。返回False继续自旋,直到超时推出。     

    3. 连锁

      InterLocked:原子操作类。提供加减、替换、递增、递减等原子操作。比较简单没什么可说的。

          

      

  • 相关阅读:
    图的存储结构(邻接表) 数据结构和算法57
    邻接多重表
    十字链表
    Java类型转换
    okHttp超时报错解决方案
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.paipaixiu/com.example.paipaixiu.MASetSomeThing}: android.view.InflateException: Binary XML file line #19: Attempt to invo
    Oracle nal() 和count(*)的注意点
    RecyclerView实现一个页面有多种item,每个item有多个view,并且可以让任意item的任意view自定义监听,通过接口方法进行触发操作
    session的一些笔记
    Android项目创建.prorperties配置文件和调用方法
  • 原文地址:https://www.cnblogs.com/bibiKu/p/2987308.html
Copyright © 2011-2022 走看看