• 深入浅出多线程系列之五:一些同步构造(下篇)


    1:CountdownEvent

    Framework 4.0提供了一个CountdownEvent类,主要是让你等待多个线程。考虑下这样的场景:

    有一个任务,3个人去做,你需要等这3个人都做完了才继续下一步操作。

    下面就是:

    class Thread15
        {
            
    static CountdownEvent _countdown = new CountdownEvent(3);

            
    public static void MainThread()
            {
                
    new Thread(SaySomething).Start("I'm thread 1");
                
    new Thread(SaySomething).Start("I'm thread 2");
                
    new Thread(SaySomething).Start("I'm thread 3");

                _countdown.Wait(); 
    //阻塞,直到Signal被调用三次
                Console.WriteLine("All threads have finished speaking!");
            }

            
    static void SaySomething(object thing)
            {
                Thread.Sleep(
    1000);
                Console.WriteLine(thing);
                _countdown.Signal();
            }
        }

    注意在构造函数中我们传递了3.代表我们要等待3个线程都结束。

    2:ThreadPool.RegisterWaitForSingleObject

    如果你的应用程序中有大量的线程都在一个WaitHandle上花费了大量的时间的时候,

    你可以通过线程池的ThreadPool.RegisterWaitForSingleObject方法来提高资源的利用率,这个方法接受一个委托,当这个WaitHandle调用signal方法后,

    方法的委托就会被执行了。 

    class Thread16
        {
            
    static ManualResetEvent _starter = new ManualResetEvent(false);

            
    public static void MainThread()
            {
                RegisteredWaitHandle reg 
    = ThreadPool.RegisterWaitForSingleObject
                    (_starter, Go, 
    "Some Data"-1true); 
          //在_starter上等待执行Go方法,-1,代表永远不超时,true代表只执行一遍,”Some Data”是传递的参数

                Thread.Sleep(
    5000);
                Console.WriteLine(
    "Signaling worker...");
                _starter.Set();     
    //唤醒等待的线程
                Console.ReadLine();
                reg.Unregister(_starter); 
    //取消注册。
            }

            
    static void Go(object data, bool timeOut)
            {
                Console.Write(
    "Started - " + data);
                Console.WriteLine(
    "ThreadId:" + Thread.CurrentThread.ManagedThreadId);
            }

        }

    3:同步上下文:

    通过继承ContextBoundObject类,并且加上Synchronization特性,CLR会自动的为你的操作加锁。

    //继承自ContextBoundObject,且加上Synchronization特性修饰
        [Synchronization]
        
    public class AutoLock:ContextBoundObject
        {
            
    public void Demo()
            {
                Console.WriteLine(
    "Start...");
                Thread.Sleep(
    1000);
                Console.WriteLine(
    "end");
            }
        }
    //主线程:
        public static void MainThread()
            {
                AutoLock safeInstance 
    = new AutoLock();
                
    new Thread(safeInstance.Demo).Start();
                
    new Thread(safeInstance.Demo).Start();
                safeInstance.Demo();
            }

    输出为:

    Start…

    End

    Start…

    End

    Start…

    End

    CLR会确保一次只有一个线程可以执行safeInstance里面的代码,它会自动的创建一个同步对象,然后

    在每次调用方法或属性的时候都 lock它,从这个角度来讲safeInstance是一个同步上下文。

    但是它是怎么样工作的,在Synchronization特性和System.Runtime.Remoting.Contexts命名空间中存在着线索。

    一个ContextBoundObject被认为是一个远程(“remote”)对象.意味所有的方法调用都可以被介入。当我们实例化AutoLock的时候,CLR实际上返回了一个proxy对象,一个和AutoLock对象有着同样方法,同样属性的Proxy对象,在这里它扮演者中介的对象。这样就为自动加锁提供了介入的机会,在每一次方法调用上都会花费几微妙的时间来介入。

    你可能会认为下面的代码会和上面的一样,是一样的输出结果:

    //继承自ContextBoundObject,且加上Synchronization特性修饰
        [Synchronization]
        
    public class AutoLock:ContextBoundObject
        {
            
    public void Demo()
            {
                Console.WriteLine(
    "Start...");
                Thread.Sleep(
    1000);
                Console.WriteLine(
    "end");
            }

            
    public void Test()
            {
                
    new Thread(Demo).Start();
                
    new Thread(Demo).Start();
                
    new Thread(Demo).Start();
                Console.ReadLine();
            }

            
    public static void RunTest()
            {
                
    new AutoLock().Test();
            }
        }

    public static void MainThread()
            {
                
    //AutoLock safeInstance = new AutoLock();
                
    //new Thread(safeInstance.Demo).Start();
                
    //new Thread(safeInstance.Demo).Start();
                
    //safeInstance.Demo();

                AutoLock.RunTest();
            }

    实际上这里我们会运行到Console.ReadLine方法这里,然后等待输入。

    为什么??

    因为CLR会确保一次只有一个线程能够执行AutoLock的代码,所以当主线程执行到Console.ReadLine方法的时候,

    就开始等待输入了。如果你按下Enter,代码就和上面的输出一样了。

    注:还有一些同步构造将在以后讲到.

    参考资料:

    http://www.albahari.com/threading/

    CLR Via C# 3.0

  • 相关阅读:
    HashMap put get 源码解析
    HashMap 源码
    配置spring boot请求的入参和出参json数据格式
    配置idea的注释模板
    基本数据类型
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
    Linux命令系列之
  • 原文地址:https://www.cnblogs.com/LoveJenny/p/2053682.html
Copyright © 2020-2023  润新知