欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-04-10 15:08:35
...
调用父类方法时,如何与子类方法,在锁对象不是同一个实例下,能线程安全,请见下面三种情况。

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

以上就是 从0自学C#13--子类和父类方法的锁对象问题的内容,更多相关内容请关注PHP中文网(www.php.cn)!