久久综合丝袜日本网手机版,日韩欧美中文字幕在线三区,亚洲精品国产品国语在线,极品在线观看视频婷婷

      <small id="aebxz"><menu id="aebxz"></menu></small>
    1. 程序員面試題

      時間:2022-07-12 02:54:25 面試 我要投稿
      • 相關(guān)推薦

      程序員面試題精選

      題目:設(shè)計(jì)一個類,我們只能生成該類的一個實(shí)例。

      程序員面試題精選

      分析:只能生成一個實(shí)例的類是實(shí)現(xiàn)了Singleton模式的類型。

      由于設(shè)計(jì)模式在面向?qū)ο蟪绦蛟O(shè)計(jì)中起著舉足輕重的作用,在面試過程中很多公司都喜歡問一些與設(shè)計(jì)模式相關(guān)的問題。在常用的模式中,Singleton是唯一一個能夠用短短幾十行代碼完整實(shí)現(xiàn)的模式。因此,寫一個Singleton的類型是一個很常見的面試題。

      事實(shí)上,要讓一個類型是能創(chuàng)建一個實(shí)例不是一件很難的事情。我們可以把該類型的構(gòu)造函數(shù)設(shè)為private,這樣該類型的用戶就不能創(chuàng)建該類型的實(shí)例了。然后我們在給類型中創(chuàng)建一個靜態(tài)實(shí)例。當(dāng)用戶需要該類型的實(shí)例時,我們就返回這個實(shí)例。基于這個思路,我們可以用C#寫出如下代碼:

      // We can only get an instance of the class Singleton1. The instance

      // is created when class Singleton1 is referenced at the first time

      public sealed class Singleton1

      {

      private Singleton1()

      {

      }

      private static Singleton1 instance = new Singleton1();

      public static Singleton1 Instance

      {

      get

      {

      return instance;

      }

      }

      }

      由于類Singleton1的實(shí)例是一個靜態(tài)變量,因此它會在該類型的第一次引用的時候被創(chuàng)建,而不是第一次在調(diào)用Singleton1.get_Instance的時候被創(chuàng)建。如果我們此時并不需要該實(shí)例,那么我們就過早地初始化該實(shí)例,無論在內(nèi)存空間還是CPU時間上都是一種浪費(fèi)。

      我們可以把上面的代碼稍作改動,就能實(shí)現(xiàn)在第一次調(diào)用Singleton_getInstance時候才會創(chuàng)建類型的唯一實(shí)例:

      // We can only get an instance of the class Singleton2.

      // The instance is created when we need it explicitly.

      public sealed class Singleton2

      {

      private Singleton2()

      {

      }

      private static Singleton2 instance = null;

      public static Singleton2 Instance

      {

      get

      {

      if (instance == null)

      instance = new Singleton2();

      return instance;

      }

      }

      }

      我們在單線程環(huán)境下只能得到類型Singleton2的一個實(shí)例,但在多線程環(huán)境下情況就可能不同了。設(shè)想如果兩個線程同時運(yùn)行到語句if (instance == null),而此時該實(shí)例的確沒有創(chuàng)建,那么兩個線程都會創(chuàng)建一個實(shí)例。此時,類型Singleton2就不在滿足模式Singleton的要求了。

      為了保證在多線程環(huán)境下我們還是只能得到類型的一個實(shí)例,我們應(yīng)該在判斷實(shí)例是否已經(jīng)創(chuàng)建,以及在實(shí)例還沒有創(chuàng)建的時候創(chuàng)建一個實(shí)例的語句上加一個同步鎖。我們把Singleton2稍作修改就得到了如下代碼:

      // We can only get an instance of the class Singleton3,

      // even when there are multiple threads which are trying

      // to get an instance concurrently.

      public sealed class Singleton3

      {

      private Singleton3()

      {

      }

      private static readonly object syncObj = new object();

      private static Singleton3 instance = null;

      public static Singleton3 Instance

      {

      get

      {

      lock (syncObj)

      {

      if (instance == null)

      instance = new Singleton3();

      }

      return instance;

      }

      }

      }

      說明一下,由于C/C++沒有為線程同步提供直接的支持。為了讓代碼顯得簡潔,而不是讓大量的代碼在實(shí)現(xiàn)同步鎖而偏離了實(shí)現(xiàn)Singleton的主題,本文的代碼用C#實(shí)現(xiàn)。

      我們還是假設(shè)有兩個線程同時想創(chuàng)建一個實(shí)例。由于在一個時刻只能有一個線程能得到同步鎖。當(dāng)?shù)谝粋線程加上鎖時,第二個線程只能在等待。當(dāng)?shù)谝粋線程發(fā)現(xiàn)實(shí)例還沒有創(chuàng)建時,它創(chuàng)建出一個實(shí)例。接著第一個線程釋放同步鎖。此時第二個線程可以加上同步鎖,并運(yùn)行接下來的代碼。由于此時實(shí)例已經(jīng)被第一個線程創(chuàng)建出來了,第二個線程就不會重復(fù)創(chuàng)建實(shí)例了。于是保證了我們只能得到一個實(shí)例。

      但是類型Singleton3還不是完美。由于我們每次調(diào)用Singleton3.get_Instance的時候,都會試圖加上一個同步鎖。由于加鎖是一個非常耗時的操作,在沒有必要的時候我們應(yīng)該盡量避免這樣的操作。

      實(shí)際上,我們只是在實(shí)例還沒有創(chuàng)建之前需要加鎖操作,以保證只有一個線程創(chuàng)建出實(shí)例。而當(dāng)實(shí)例已經(jīng)創(chuàng)建之后,我們已經(jīng)不需要再做加鎖操作了。于是,我們可以把上述代碼再作進(jìn)一步的改進(jìn):

      // We can only get an instance of the class Singleton4,

      // even when there are multiple threads which are trying

      // to get an instance concurrently. When the instance has

      // been created, we dont need the lock any more.

      public sealed class Singleton4

      {

      private Singleton4()

      {

      }

      private static object syncObj = new object();

      private static Singleton4 instance = null;

      public static Singleton4 Instance

      {

      get

      {

      if (instance == null)

      {

      lock (syncObj)

      {

      if (instance == null)

      instance = new Singleton4();

      }

      }

      return instance;

      }

      }

      }

      我們只需要在最開始調(diào)用Singleton4_getInstance(可能來自一個線程,也可能來自多個線程)的時候需要加鎖。當(dāng)實(shí)例已經(jīng)創(chuàng)建之后,我們就不再需要作加鎖操作,從而在后續(xù)調(diào)用Singleton4_getInstance時性能得到提升。

      關(guān)于第一種寫法的更多,請參考 。站在面試的角度,本文的分析已經(jīng)足夠應(yīng)付。但如果想展示更多對多線程編程的理解,更深入地了解這個問題總是有益的。