"C#用两个线程交替打印1-100的五种方法"是.NET工程师面试多线程常考的试题之一,主要考察对C#语法和对多线程的熟悉程度。本文将用5种方法实现这个面试题。
方法1:使用Mutex或lock
这种方法涉及使用Mutex或lock对象来同步两个线程。其中一个线程负责打印偶数,另一个线程负责打印奇数。线程在执行任务之前会锁定共享的Mutex或lock对象,以确保每个线程执行任务时只有一个线程能够访问共享资源。代码如下:.
class Program
{
static Mutex mutex = new Mutex();
static int count = 1;
static void Main(string[] args)
{
Thread t1 = new Thread(PrintOddNumbers);
Thread t2 = new Thread(PrintEvenNumbers);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadLine();
}
static void PrintOddNumbers()
{
while (count <= 100)
{
mutex.WaitOne();
if (count % 2 == 1)
{
Console.WriteLine("Thread 1: " + count);
count++;
}
mutex.ReleaseMutex();
}
}
static void PrintEvenNumbers()
{
while (count <= 100)
{
mutex.WaitOne();
if (count % 2 == 0)
{
Console.WriteLine("Thread 2: " + count);
count++;
}
mutex.ReleaseMutex();
}
}
}
方法2:使用AutoResetEvent
AutoResetEvent是一种线程同步机制,允许一个线程等待另一个线程发出信号来继续执行。其中一个线程负责打印奇数,另一个线程负责打印偶数。当一个线程完成打印任务时,它发出信号以唤醒另一个线程来继续执行。
class Program
{
static AutoResetEvent oddEvent = new AutoResetEvent(false);
static AutoResetEvent evenEvent = new AutoResetEvent(false);
static int count = 1;
static void Main(string[] args)
{
Thread t1 = new Thread(PrintOddNumbers);
Thread t2 = new Thread(PrintEvenNumbers);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadLine();
}
static void PrintOddNumbers()
{
while (count <= 100)
{
if (count % 2 == 1)
{
Console.WriteLine("Thread 1: " + count);
count++;
evenEvent.Set();
oddEvent.WaitOne();
}
}
}
static void PrintEvenNumbers()
{
while (count <= 100)
{
if (count % 2 == 0)
{
Console.WriteLine("Thread 2: " + count);
count++;
oddEvent.Set();
evenEvent.WaitOne();
}
}
}
//欢迎关注公众号“DOTNET开发跳槽”,关注可获得海量面试题
方法3:使用Monitor
Monitor是C#中的一种同步机制,类似于Mutex。其中一个线程负责打印奇数,另一个线程负责打印偶数。线程在执行任务之前会锁定共享的Monitor对象,以确保每个线程执行任务时只有一个线程能够访问共享资源。
class Program
{
static object lockObj = new object();
static int count = 1;
static void Main(string[] args)
{
Thread t1 = new Thread(PrintOddNumbers);
Thread t2 = new Thread(PrintEvenNumbers);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadLine();
}
static void PrintOddNumbers()
{
while (count <= 100)
{
lock (lockObj)
{
if (count % 2 == 1)
{
Console.WriteLine("Thread 1: " + count);
count++;
}
}
}
}
static void PrintEvenNumbers()
{
while (count <= 100)
{
lock (lockObj)
{
if (count % 2 == 0)
{
Console.WriteLine("Thread 2: " + count);
count++;
}
}
}
}
}
方法4:使用信号量Semaphore
Semaphore是一种同步机制,允许多个线程同时访问共享资源。其中一个线程负责打印奇数,另一个线程负责打印偶数。线程在执行任务之前会等待信号量,以确保每个线程只有在获得信号量之后才能访问共享资源。
class Program
{
static Semaphore semaphore = new Semaphore(1, 1);
static int count = 1;
static void Main(string[] args)
{
Thread t1 = new Thread(PrintOddNumbers);
Thread t2 = new Thread(PrintEvenNumbers);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadLine();
}
static void PrintOddNumbers()
{ //注意 这里是99,否则会出现101
while (count <= 99)
{
semaphore.WaitOne();
if (count % 2 == 1)
{
Console.WriteLine("Thread 1: " + count);
count++;
}
semaphore.Release();
}
}
static void PrintEvenNumbers()
{
while (count <= 100)
{
semaphore.WaitOne();
if (count % 2 == 0)
{
Console.WriteLine("Thread 2: " + count);
count++;
}
semaphore.Release();
}
}
}
方法5:使用Task和async/await
在C#中,使用Task和async/await关键字可以轻松地在两个线程之间切换执行。其中一个线程负责打印奇数,另一个线程负责打印偶数。线程在执行任务之前使用async/await等待异步任务完成,以确保每个线程只在异步任务完成后才访问共享资源。
class Program
{
static int count = 1;
static void Main(string[] args)
{
Task.Run(PrintOddNumbers);
// 这里改成这个也可以
// var thread1 = new Thread(PrintOddNumbers);
Task.Run(PrintEvenNumbers);
Console.ReadLine();
}
//如果用Thread改成同步方法
static async Task PrintOddNumbers()
{
while (count <= 100)
{
if (count % 2 == 1)
{
Console.WriteLine("Thread 1: " + count);
count++;
//如果用Thread这里改成 Thread.Sleep(1);
await Task.Delay(1);
}
}
}
static async Task PrintEvenNumbers()
{
while (count <= 100)
{
if (count % 2 == 0)
{
Console.WriteLine("Thread 2: " + count);
count++;
await Task.Delay(1);
}
}
}
//欢迎关注公众号“DOTNET开发跳槽”,关注可获得海量面试题
五种效果如下:
考察的知识点