C#用两个线程交替打印1-100

这是很常见的面试题,练练基础。

方法一 :利用Mutex方法

注意:下面两行红色部分。没有这个判断的时候,奇数会多出一个101。

if (count % 2 == 1 && count <= 100)

if (count % 2 == 0 && count <= 100)

 internal class Program
 {
     static Mutex mutex = new Mutex();
     static int count = 1;
     static void Main(string[] args)
     {
         Thread tOdd = new Thread(PrintOddNumbers);
         Thread tEven = new Thread(PrintEvenNumbers);
         tOdd.Start();
         tEven.Start();
         tOdd.Join();
         tEven.Join();
         Console.ReadLine();
     }


     static void PrintOddNumbers()
     {
         Thread.CurrentThread.Name = "奇数";
         while (count <=100)
         {
             mutex.WaitOne();
             if (count % 2 == 1 && count <= 100)
             {
                 Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                 count++;
             }
             mutex.ReleaseMutex();
         }

         
     }

     static void PrintEvenNumbers()
     {
         Thread.CurrentThread.Name = "偶数";
         while (count <= 100)
         {
             mutex.WaitOne();
             if (count % 2 == 0 && count <= 100)
             {
                 Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                 count++;
             }
             mutex.ReleaseMutex();
         }
     }
 }
方法二:利用Monitor类方法

与方法一代码非常相似。

internal class Program
{
    static object lockObj = new object();

    static int count = 1;
    static void Main(string[] args)
    {
        Thread tOdd = new Thread(PrintOddNumbers);
        Thread tEven = new Thread(PrintEvenNumbers);
        tOdd.Start();
        tEven.Start();
        tOdd.Join();
        tEven.Join();
        Console.ReadLine();
    }


    static void PrintOddNumbers()
    {
        Thread.CurrentThread.Name = "奇数";
        while (count <=100)
        {
            lock (lockObj)
            {
                if (count % 2 == 1 && count <= 100)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                    count++;
                }
            }
        }

        
    }

    static void PrintEvenNumbers()
    {
        Thread.CurrentThread.Name = "偶数";
        while (count <= 100)
        {
            lock (lockObj)
            {
                if (count % 2 == 0)//&& count <= 100)
                {
                    Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                    count++;
                }
            }
        }
    }
}
方法三:利用AutoResetEvent

AutoResetEvent也是一种线程同步机制。

Set : 释放等待的线程

Waitone:等待信号

internal class Program
{
    static AutoResetEvent oddEvent = new AutoResetEvent(false);
    static AutoResetEvent evenEvent = new AutoResetEvent(false);

    static int count = 1;
    static void Main(string[] args)
    {
        Thread tOdd = new Thread(PrintOddNumbers);
        Thread tEven = new Thread(PrintEvenNumbers);
        tOdd.Start();
        tEven.Start();
        tOdd.Join();
        tEven.Join();
        Console.ReadLine();
    }


    static void PrintOddNumbers()
    {
        Thread.CurrentThread.Name = "奇数";
        while (count <=100)
        {

            if (count % 2 == 1)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
                evenEvent.Set();
                oddEvent.WaitOne();
            }
            
        }

        
    }

    static void PrintEvenNumbers()
    {
        Thread.CurrentThread.Name = "偶数";
        while (count <= 100)
        {
            if (count % 2 == 0)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
                oddEvent.Set();
                evenEvent.WaitOne();
            }
        }
    }
}
方法四 Semaphore类
Semaphore(Int32, Int32)

初始化 Semaphore 类的新实例,并指定初始入口数和最大并发入口数。

internal class Program
{

    static Semaphore semaphore = new Semaphore(1, 1);

    static Mutex mutex = new Mutex();

    static int count = 1;
    static void Main(string[] args)
    {
        Thread tOdd = new Thread(PrintOddNumbers);
        Thread tEven = new Thread(PrintEvenNumbers);
        tOdd.Start();
        tEven.Start();
        tOdd.Join();
        tEven.Join();
        
        Console.ReadLine();
    }


    static void PrintOddNumbers()
    {
        Thread.CurrentThread.Name = "奇数";
        while (count <= 100)
        {
            semaphore.WaitOne();
            if (count % 2 == 1 && count <= 100)
            {                   
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
            }
            semaphore.Release();
        }


    }

    static void PrintEvenNumbers()
    {
        Thread.CurrentThread.Name = "偶数";
        while (count <= 100)
        {
            semaphore.WaitOne();
            if (count % 2 == 0)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
            }
            semaphore.Release();
        }
    }
}
方法五 Task

awit/async 是.Net 4.5才开始用的。 用这两个方法,很容易实现两个线程之间的切换。

微软对Task底层做了很多,用起来简单,深入了解比较难。在下面的文档里提到了线程,线程池,并行任务等等概念,可以作为补充了解。

Task Parallel Library (TPL) - .NET | Microsoft Learn

internal class Program
{

    static int count = 1;
    static void Main(string[] args)
    {
        Task.Run(()=> PrintOddNumbers("奇数"));
        Task.Run(() => PrintEvenNumbers("偶数"));

        Console.ReadLine();
    }


    static async Task PrintOddNumbers(string name)
    {
        //Thread.CurrentThread.Name = "奇数";
        while (count <= 100)

            if (count % 2 == 1)
            {
                //Task 调用的是线程池,不一定每次都是同一个线程,所以Name的值可能为空
                //Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                Console.WriteLine(name + ":" + count);
                count++;
                await Task.Delay(1);
            }

    }


    static async Task PrintEvenNumbers(string name)
    {
        //Thread.CurrentThread.Name = "偶数";
        while (count <= 100)
        {
            if (count % 2 == 0)
            {
                Console.WriteLine(name + ":" + count);
                count++;
                await Task.Delay(1);
            }
        }
    }
}

拓展:

如果有三个线程,轮流打印。选择哪个方法比较简单呢?方法三

internal class Program
{
    static AutoResetEvent oneEvent = new AutoResetEvent(false);
    static AutoResetEvent twoEvent = new AutoResetEvent(false);
    static AutoResetEvent threeEvent = new AutoResetEvent(false);

    static int count = 1;
    static void Main(string[] args)
    {
        Thread tOne = new Thread(PrintOne);
        Thread tTwo = new Thread(PrintTwo);
        Thread tThree = new Thread(PrintThree);
        tOne.Start();
        tTwo.Start();
        tThree.Start();
        tOne.Join();
        tTwo.Join();
        tThree.Join();

        Console.ReadLine();
    }


    static void PrintOne()
    {
        Thread.CurrentThread.Name = "Thread 1";
        while (count <= 20)
        {
            if (count % 3 == 1 && count <= 20)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
            }
            twoEvent.Set();
            oneEvent.WaitOne();
        }
    }
    static void PrintTwo()
    {
        Thread.CurrentThread.Name = "Thread 2";
        while (count <= 20)
        {
            if (count % 3 == 2 && count <= 20)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
            }
            threeEvent.Set();
            twoEvent.WaitOne();
        }
    }

    static void PrintThree()
    {
        Thread.CurrentThread.Name = "Thread 3";
        while (count <= 20)
        {
            if (count % 3 == 0 && count <= 20)
            {
                Console.WriteLine(Thread.CurrentThread.Name + ":" + count);
                count++;
            }
            oneEvent.Set();
            threeEvent.WaitOne();
        }
    }
}

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值