C#之:线程同步 Lock语句

Lock 语句:

Lock是C#中的关键字,他要锁定一个资源,lock的特点是:同时只能有一个线程进入lock的对象的范围,其他lock的线程就要等。Lock语句时设定锁定和解除锁定的一种简单方式。
注意:lock要锁定同一个对象,而且必须是引用类型的对象

        private static int countec = 0;
        private static object obj = new object();
        static void Main(string[] args)
        {
            Thread t1 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    lock(obj) //注意lock要锁定同一个对象,而且必须是引用类型的对象
                    {
                        countec++; //自增1000次
                    }
                   
                    Thread.Sleep(1);
                }
            });
            t1.Start();
            Thread t2 = new Thread(() =>
            {
                for (int i = 0; i < 1000; i++)
                {
                    lock (obj)//注意lock要锁定同一个对象,而且必须是引用类型的对象
                    {
                        countec++; //自增1000次
                    }
                    Thread.Sleep(1);
                }
            });
            t2.Start();
            t1.Join();
            t2.Join();

            Console.WriteLine(countec); //输出2000
            /*
             * 改用lock解决多个线程同时操作一个资源。lock是C#中的关键字,他要锁定一个资源,lock的特点是:同时只能有一个线程进入lock的对象的范围,其他lock的线程就要等。
             */
            Console.ReadKey();
        }

输出结果:

在这里插入图片描述
注意:在一个地方使用Lock语句并不意味者,访问对象的其他线程都正在等待。必须对每个访问共享状态的线程显式地使用同步功能。

死锁:

过多的锁定也会有麻烦,容易产生死锁。在死锁中至少有两个线程被挂起,并等待对方解除锁定。由于两个线程都在 等待对方解除锁定,就会出现死锁现象,程序将无限等待下去。

例:

 public  class StateObject
    {
        private int state = 10;
        private object locker = new object();
        public void ChangeState(int loop)
        {
            lock(locker)
            {
                if(state==10)
                {
                    state++;
                    Trace.Assert(state == 11, "竞态条件发生在" + loop + "loops");
                }
                state = 10;
            }
        }
    }
 public  class SampleTack
    {
        private StateObject state1;
        private StateObject state2;
        public SampleTack(StateObject s1,StateObject s2)
        {
            this.state1 = s1;
            this.state2 = s2;
        }

        public void Deadlock1()
        {
            int i = 0;
            while(true)
            {
                lock(state1)
                {
                    lock(state2)
                    {
                        state1.ChangeState(i);
                        state2.ChangeState(i++);
                        Console.WriteLine("仍在运行:{0}",i);
                    }
                }
            }
        }

        public void Deadlock2()
        {
            int i = 0;
            while (true)
            {
                lock (state2)
                {
                    lock (state1)
                    {
                        state1.ChangeState(i);
                        state2.ChangeState(i++);
                        Console.WriteLine("仍在运行:{0}", i);
                    }
                }
            }
        }
    }

调用:

 static void Main(string[] args)
        {
            var st1 = new StateObject();
            var st2 = new StateObject();
            new Task(new SampleTack(st1, st2).Deadlock1).Start();
            new Task(new SampleTack(st1, st2).Deadlock2).Start();

            Console.ReadKey();
        }

在这里插入图片描述
结果程序只在控制台输出1次,就没有响应了。
调试模式打开,选择 “全部中断” ,选择 “窗口” 点击 “任务”。
可是看到是锁死状态。
在这里插入图片描述
有时候死锁并不像上面例子那么明显。一个线程锁定了 st1,接着锁定了 st2;另一个线程锁定了st2,接着锁定了st1。在本例中只要改变锁定的顺序,这两个线程就会以相同的顺序进行锁定。但是,锁定可能隐藏在方法的深处。为了避免这个问题,可以在程序的体系架构中,从一开始就设计好锁定顺序,也可以为锁定定义超时时间。

方法上标注[MethodImpl(MethodImplOptions.Synchronized)],这样一个方法只能同时被一个线程访问。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值