从0自学C#13--子类和父类方法的锁对象问题

调用父类方法时,如何与子类方法,在锁对象不是同一个实例下,能线程安全,请见下面三种情况。

case1:

如下代码,在调用父类的方法时,和子类的方法,发生线程安全问题。原因的锁对象的实例不是同一个。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ForTest//check the lock object for thread safety
{
    class Program
    {
        static void Main(string[] args)
        {
            son myson = new son();
            Parallel.For(0, 5, (int i) =>
             {
                 myson.methodA();
                 myson.methodC();
             });
            Console.ReadKey();
        }
    }

    public class grandfather
    {
        //protected static object syncRoot = new object();
    }

    public class father:grandfather
    {
        private static object syncRoot = new object();
        protected int cont = 0;

        public virtual bool methodA()
        {
            lock (syncRoot)
            {
                cont++;
                Thread.Sleep(1000);
                Console.WriteLine("cout++ is " + cont);
                return true;
            }
        }

        public virtual bool methodB()
        {
            lock (syncRoot)
            {
                return true;
            }
        }
    }

    public class son:father
    {
        private static object syncRoot = new object();

        public bool methodC()
        {
            lock (syncRoot)
            {
                cont += 2;
                Thread.Sleep(2000);
                Console.WriteLine("cont += 2 is " + cont);
                return true;
            }
        }
    }
}

输出:

cout++ is 1
cout++ is 4
cont += 2 is 5
cout++ is 5
cout++ is 8
cont += 2 is 9
cout++ is 11
cont += 2 is 11
cont += 2 is 13
cont += 2 is 15

case2:

case1的解决方法是,在父类初始化锁对象,让子类继承。这样就线程安全了。如下。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ForTest//check the lock object for thread safety
{
    class Program
    {
        static void Main(string[] args)
        {
            son myson = new son();
            Parallel.For(0, 5, (int i) =>
             {
                 myson.methodA();
                 myson.methodC();
             });
            Console.ReadKey();
        }
    }

    public class grandfather
    {
        protected static object syncRoot = new object();
    }

    public class father:grandfather
    {
        protected int cont = 0;

        public virtual bool methodA()
        {
            lock (syncRoot)
            {
                cont++;
                Thread.Sleep(1000);
                Console.WriteLine("cout++ is " + cont);
                return true;
            }
        }

        public virtual bool methodB()
        {
            lock (syncRoot)
            {
                return true;
            }
        }
    }

    public class son:father
    {
        public bool methodC()
        {
            lock (syncRoot)
            {
                cont += 2;
                Thread.Sleep(2000);
                Console.WriteLine("cont += 2 is " + cont);
                return true;
            }
        }
    }
}

输出:

cout++ is 1
cout++ is 2
cont += 2 is 4
cout++ is 5
cout++ is 6
cout++ is 7
cont += 2 is 9
cont += 2 is 11
cont += 2 is 13
cont += 2 is 15

case3:

当然有些特殊情况下,子类硬要重新实例化一个锁对象。如何避免上面第一种线程安全问题发生?需要:

  • 子类加锁重写父类分方法(如果父类methodA是虚方法)

或者

  • new一下(如果父类methodA是实例方法)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ForTest//check the lock object for thread safety
{
    class Program
    {
        static void Main(string[] args)
        {
            son myson = new son();
            Parallel.For(0, 5, (int i) =>
             {
                 myson.methodA();
                 myson.methodC();
             });
            Console.ReadKey();
        }
    }

    public class grandfather
    {
        protected static object syncRoot = new object();
    }

    public class father:grandfather
    {
        protected int cont = 0;

        public virtual bool methodA()
        {
            lock (syncRoot)
            {
                cont++;
                Thread.Sleep(1000);
                Console.WriteLine("cout++ is " + cont);
                return true;
            }
        }

        public virtual bool methodB()
        {
            lock (syncRoot)
            {
                return true;
            }
        }
    }

    public class son:father
    {
        private static object sync = new object();

        public override bool methodA()//重写
        {
            lock (sync)
            {
                return base.methodA();
            }
        }

        public bool methodC()
        {
            lock (sync)
            {
                cont += 2;
                Thread.Sleep(2000);
                Console.WriteLine("cont += 2 is " + cont);
                return true;
            }
        }
    }
}


        public new bool methodA()\\new一下
        {
            lock (sync)
            {
                return base.methodA();
            }
        }

输出:

cout++ is 1
cout++ is 2
cont += 2 is 4
cout++ is 5
cout++ is 6
cout++ is 7
cont += 2 is 9
cont += 2 is 11
cont += 2 is 13
cont += 2 is 15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值