这是很常见的面试题,练练基础。
方法一 :利用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();
}
}
}