• static与线程安全 -摘自网络


    在.Net中,Static会经常和线程的东西扯在一起。写的代码是不是线程安全呢?好多程序员都在想,不过,有时候随便就放过了。真正出问题的时候再想。其实,如果程序员一开始就明白这里面的机制,也许,编写的代码质量会更加的高。也少些线程安全的烦问题。事实上,了解线程安全的机制后,你会发现,这原来是很简单的事情,只是很多人不愿意去了解线程。因为对于普通的程序员,线程的东西真是不好玩的,也不太过瘾,同时好容易出错。
    
    生活中的例子
    顾客一次买了10个产品去收银处交钱,一般来说,收银处的框台应该很多的,顾客可以选一个人少的结帐就行了。而收银员可以一个个顾客地处理。这当然是有条不紊的事了。实际上,每个收银员就是一个线程,如果一个框台对于一个收银员的话,也就真是没有问题了。框台就是一个资源。
    但是对于操作系统而言,资源往往是很宝贵的,要提供给多个收银员使用。即线程共享地使用资源。而操作系统的调度经常是没有道理的,也就是随意性很大。一时由收银员A操作,一时由收银员B操作。
    试想想,收银员A,B都不能很好地做自己的事情,而且操作的数据会很混乱。也根本不知道对不对。不过,如果收银员A可以在一段时间内独占框台,事情也就会很容易了。这样虽然导致排队的用户很多,效率也低,但是每一个顾客的数据都处理正确的。
    这其实就是线程安全的问题,如果一个线程把资源锁住了,别的线程在排除,数据就会很正确的。
    
    Static代码例子
    下面的代码,无论你使用多少的线程来控件,都是安全的。因为线程之间,不会共享什么资源,唯一相同的是使用了同一个逻辑。其实这是在破坏线程的前题方面下功夫,出现线程不安全的条件都没有了,那肯定就是线程安全的。
    class CheckoutLane
    {
        public static float GetTotal(Cart cart)
        {
            float total = 0;
    
            for (int i = 0; i < cart.GroceryItems.Length; i++)
            {
                total += cart.GroceryItems[i].Price; 
                Thread.Sleep(100);
            }
            return total;
        }
    
    }
    而下面的代码,不是线程安全的,因为共享了static float total;这个资源,而各个线程都随机都被调用,可以任意修改total这个数据。这个,就正如多个收银员共享柜台,任意执行收银操作一样。
    class CheckoutLane
    {
        static float total;
    
        public static float GetTotal(Cart cart)
        {
            total = 0;
    
            for (int i = 0; i < cart.GroceryItems.Length; i++)
            {
                total += cart.GroceryItems[i].Price;  
                Thread.Sleep(100);
            }
            return total;
        }
    
    }
    下面的代码是线程安全的,使用了lock关键字,可以达到一个线程强占资源的效果。这时,synchLock就作为了共享的资源,被某一个线程锁住了。
    class CheckoutLane
    {
        static float total;
        static object synchLock = new object();
    
        public static float GetTotal(Cart cart)
        {
            lock(synchLock)
            {
                total = 0;
    
                for (int i = 0; i < cart.GroceryItems.Length; i++)
                {
                    total += cart.GroceryItems[i].Price;  
                    Thread.Sleep(100);
                }
                return total;
            }
        }
    }
    
  • 相关阅读:
    英文文法学习笔记(14)分词
    利用别名简化进入docker容器数据库的操作
    英文文法学习笔记(12)形容词
    小知识:在Exadata平台上使用ExaWatcher收集信息
    小知识:调整OCI实例的时区
    小知识:Docker环境缺少vi命令,如何解决
    小知识:Exadata平台去掉密码输错延迟10分钟登录
    英文文法学习笔记(13)副词
    SpringBoot,SpringMvc 参数校验 用法详解
    java 获取项目根路径、获取桌面路径
  • 原文地址:https://www.cnblogs.com/haoliansheng/p/3224828.html
Copyright © 2020-2023  润新知