"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開發跳槽”,關注可獲得海量面試題
五種效果如下:
以上五種方法各有優缺點,沒有一種方法是絕對最優的,取決于應用場景和要求,以下是對五種方法的簡單比較和說明:1、使用ManualResetEventWaitHandle:這種方法在實作上較為簡單,但是由于執行緒必須互斥地訪問共享資源,因此會導致性能瓶頸,此外,使用ManualResetEventWaitHandle需要頻繁呼叫WaitOne和Set方法,可能會降低應用程式的回應能力,2、使用AutoResetEventWaitHandle:這種方法在實作上比較簡單,而且使用AutoResetEventWaitHandle可以避免性能瓶頸問題,然而,它仍然需要頻繁呼叫WaitOne和Set方法,可能會降低應用程式的回應能力,3、使用鎖:使用鎖可以避免性能瓶頸問題,因為同一時間只有一個執行緒可以訪問共享資源,但是,鎖可能會導致執行緒死鎖和性能下降的問題,因此需要小心使用,4、使用信號量Semaphore:這種方法可以避免性能瓶頸問題,并允許多個執行緒同時訪問共享資源,Semaphore還可以設定多個許可證,以控制并發執行緒的數量,然而,使用Semaphore可能會使代碼變得更加復雜,因此需要小心使用,5、使用Task和async/await:這種方法可以避免性能瓶頸問題,并且使用Task和async/await可以使代碼更加簡潔易懂,但是,它可能會對記憶體和CPU產生額外的開銷,因為需要在任務之間頻繁地切換背景關系,綜上所述,選擇哪種方法取決于應用程式的要求和程式員的個人偏好,如果應用程式需要更好的性能,則應該使用鎖或信號量;如果應用程式需要更簡潔易懂的代碼,則應該使用Task和async/await,
考察的知識點
1、C#編程語言和語法:實作多執行緒程式需要熟悉C#編程語言和語法,包括執行緒的創建和管理、共享資源的訪問和同步等方面的知識,2、多執行緒編程:多執行緒編程是指同時運行多個執行緒的編程模型,它可以提高應用程式的性能和回應能力,多執行緒編程需要考慮執行緒的同步、共享資源的訪問、執行緒間的通信等問題,3、執行緒同步機制:執行緒同步機制是指用于控制多個執行緒訪問共享資源的機制,常用的執行緒同步機制包括鎖、信號量、事件等,4、異步編程:異步編程是指不阻塞執行緒并且在完成任務后通知執行緒的編程模型,它可以提高應用程式的回應能力和性能,異步編程需要熟悉異步和await關鍵字、Task和Task<T>等型別、async和await方法等概念,參考:chatGPT轉載請註明出處,本文鏈接:https://www.uj5u.com/net/547588.html
標籤:.NET技术