• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
【我是谁】
博客园    首页    新随笔    联系   管理    订阅  订阅

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类型,如果传进来一个值类型,就会装箱,产生一个新的对象!那么这两次操作的对象都不是同一个对象,不是同一个地址,

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

 

 

posted @ 2017-12-11 23:06  【我是谁】  阅读(227)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3