• Lock


    一、线程同步,先来看一下一段代码:

     Thread t1 = new Thread(new ThreadStart(() =>
                {
                    //1.递增
                    for (int i = 0; i < 10000000; i++)
                    {
                        _count++;
                        //_count = _count + 1;//分为3个步骤,取到_count的值,把_count的值加1,把计算好的值重新赋值给_count
                    }
                }));
                t1.Start();
                Console.WriteLine("t1线程已经启动,开始对_count变量++");
                Console.WriteLine("主线程继续执行.....");
                //2.递减
                for (int i = 0; i < 10000000; i++)
                {
                    _count--;
                }
    
                //到这里的时候要保证主线程的--操作与t1线程的++操作都执行完毕
                //等待t1执行完毕
                t1.Join();
                Console.WriteLine("_count结果是:{0}", _count);
                Console.ReadKey();
    

    结果是:

    这个结果是不是很惊讶?因为_count++或者_count--分为上述三个步骤! 线程什么时候执行或者暂停是由cpu决定的,我们可能在准备++的时候拿到的_count的值是1000,

    但是线程暂停了,去执行_count--,它那边拿到的值也是1000,线程可能又转去执行++完之后是1001,赋给_count,但是之后执行--是999,再次赋给_count,结果就不对了。

    二、解决并发访问变量问题

      static readonly object objSync = new object();
     Thread t1 = new Thread(new ThreadStart(() =>
                {
                    //1.递增
                    for (int i = 0; i < max; i++)
                    {
                        lock (objSync)//向系统申请可不可以 锁定objSync对象 如果objSync对象没有被锁定,那么可以 如果objSync对象呗锁定了,那么这个语句会暂停,直到申请到mobjSync
    //对象 { //在lock块中的代码同时只能有一个线程来访问。 _count++; }//释放第objSync的锁定 } })); t1.Start(); Console.WriteLine("t1线程已经启动,开始对_count变量++"); Console.WriteLine("主线程继续执行....."); //2.递减 //加锁后执行变慢!! for (int i = 0; i < max; i++) { lock (objSync) { _count--; } } //到这里的时候要保证主线程的--操作与t1线程的++操作都执行完毕 //等待t1执行完毕 t1.Join(); Console.WriteLine("_count结果是:{0}", _count); Console.ReadKey();

    锁的本质是什么呢?我们反编译一下代码:

    可以看到就是  Monitor.Enter与  Monitor.Exit,我们改造一下上面的代码:

      Thread t1 = new Thread(new ThreadStart(() =>
                {
                    //1.递增
                    for (int i = 0; i < max; i++)
                    {
                        //lock (objSync)
                        //{
                        //    //在lock块中的代码同时只能有一个线程来访问。
                        //    _count++;
                        //}
                        //标记当前是否已经上锁
                        bool isLockOk = false;
                        //上锁
                        Monitor.Enter(objSync, ref isLockOk);
                        try
                        {
                            _count++;
                        }
                        finally
                        {
                            if (isLockOk)
                            {
                                Monitor.Exit(objSync);
                            }
                        }
    
                    }
                }));
                t1.Start();
                Console.WriteLine("t1线程已经启动,开始对_count变量++");
                Console.WriteLine("主线程继续执行.....");
                //2.递减
                //加锁后执行变慢!!
                for (int i = 0; i < max; i++)
                {
                    lock (objSync)
                    {
                        _count--;
                    }
    
                }
                t1.Join();
                Console.WriteLine("_count结果是:{0}", _count);
                Console.ReadKey();
    

    锁住的对象为什么不能是值类型呢?

    Monitor.Enter或者Monitor.Exit的参数是object类型,如果传进来一个值类型,就会装箱,产生一个新的对象!那么这两次操作的对象都不是同一个对象,不是同一个地址,

    所以只能用引用类型来当做所变量。

     

  • 相关阅读:
    展示hive表大小的topN
    磁盘满了的解决思路
    软连接使用心得
    CDH部署spark2 的时候 cloudera manager报错“客户端配置 (id=2) 已使用 1 退出,而预期值为 0
    CDH下载源的配置
    Supervisor 安装配置
    人工智能深度学习:TensorFlow2.0如何结构化数据分类?
    人工智能深度学习:TensorFlow2.0如何解决过拟合和欠拟合问题?
    人工智能深度学习:如何使用TensorFlow2.0实现文本分类?
    人工智能深度学习:使用TensorFlow2.0实现图像分类
  • 原文地址:https://www.cnblogs.com/entclark/p/8025506.html
Copyright © 2020-2023  润新知