Java多線程題庫


一、    填空題

  1. 處於運行狀態的線程在某些情況下,如執行了sleep(睡眠)方法,或等待I/O設備等資源,將讓出CPU並暫時停止自己的運行,進入____阻塞_____狀態。
  2. 處於新建狀態的線程被啟動后,將進入線程隊列排隊等待CPU,此時它已具備了運行條件,一旦輪到享用CPU資源就可以獲得執行機會。上述線程是處於    就緒    狀態。

解析: 線程的生命周期—五個階段

        新建狀態---- new關鍵字創建線程對象

        就緒狀態---- start()方法運行之前

        運行狀態---- run()方法的運行

        堵塞狀態--- interrupt()  sleep()  join()  yield()  wait() 等方法

        死亡狀態--- stop()方法(已過時) /或run()方法運行結束

  1. 一個正在執行的線程可能被人為地中斷,讓出CPU的使用權,暫時中止自己的執行,進入     阻塞       狀態。

解析:人為的中斷正在執行的線程---- 執行wait() 、interrupt() 、sleep()方法等

  1. 在Java中編寫實現多線程應用有兩種途徑:一種是繼承Thread類創建線程,另一種是實現    Runnable         接口創建線程。

解析: 繼承Thread類來創建線程,不能實現資源的共享,除非資源使用static修飾。

       實現Runnable接口創建線程,此時還需要借助Thread類,因為Runnable接口

       沒有start()方法,同時Thread類是Runnable接口的子類….

  1. 在線程控制中,可以調用_____join()____方法,阻塞當前正在執行的線程,等插隊線程執行完后后再執行阻塞線程。
  2. 多線程訪問某個共享資源可能出現線程安全問題,此時可以使用______synchronized_____關鍵字來實現線程同步,從而避免安全問題出現,但會影響性能,甚至出現死鎖。
  3.  在線程通信中,調用wait( )可以是當前線程處於等待狀態,而為了喚醒一個等待的線程,需要調用的方法是____notify()/notifyAll()__________。

解析:線程等待使用wait()方法,此方法最先是存在於Object類,Thread類繼承Object類,可以獲取此方法,同時notify()方法和notifyAll()方法---線程喚醒,最先也是存在於

Object類當中。

  1. 在線程通信中,可以調用wait()、notify()、notifyAll()三個方法實現線程通信,這三個方法都是____Object____類提供的public方法,所以任何類都具有這三個方法。

 

二、    選擇題

1.

下列關於Java線程的說法正確的是(   A )。(選擇一項)

 

 

 

 

A

每一個Java線程可以看成由代碼、一個真實的CPU以及數據三部分組成

 

B.

創建線程的兩種方法中,從Thread類中繼承方式可以防止出現多父類的問題

 

C.

Thread類屬於java.util程序包

 

D.

使用new Thread(new X()).run();方法啟動一個線程

解析:

     A、語句正確。

     B、創建線程兩種方法:一是繼承Thread類,一是實現Runnable接口

        根據Java語言類的單繼承特性,防止出現多繼承,但是可以實現多

        重繼承,也可以出現多父類。

C、Thread類是存在於java.lang包下

     D、啟動一個線程是調用start()方法,之后JVM會默認的調用run()方法

        run()方法是線程的主體,核心代碼放到此方法當中。

 

2.

以下選項中可以填寫到橫線處,讓代碼正確編譯和運行的是(  AD  。(選擇一項)

 

public class Test implements Runnable {

         public static void main(String[] args) {

                   ___________________________________

                   t.start();

                   System.out.println("main");

         }

         public void run() {

                   System.out.println("thread1!");

         }

}

 

 

 

 

A.

Thread t = new Thread(new Test());

 

B.

Test t = new Test();

 

C.

Thread t = new Test();          

 

D.

Thread t = new Thread();

解析:

  線程的創建有兩種方式,其中之一就是實現Runnable接口。

  此接口只有一個抽象方法---run()方法,啟動線程又需要start()方法

  此時還需要借助Thread類,根據Thread類的構造方法:

Public  Thread(Runnable  run)

需要傳入Runnable接口對象

 此題還有一個方法: 直接創建Thread類對象,調用start()方法

所以D選項也是正確的,但是此題重點還是考的子類實現Runnable接口

根據Thread類的構造方法啟動線程。

 

3.

如下代碼創建一個新線程並啟動線程,問:四個選項中可以保證正確代碼創建target對象,並能編譯正確的是(   C  )?(選擇一項)

 

public static void main(String[] args) {

          Runnable target=new MyRunnable( ); 

          Thread myThread=new Thread(target);

}

 

 

 

 

A

public class MyRunnable extends Runnable {

         public void run( ) {        }

}

 

B.

public class MyRunnable extends Runnable {

         void run( ) {  }

}

 

C.

public class MyRunnable  implements Runnable  {

         public void run( ) {        }

}

 

D.

public class MyRunnable  implements Runnable  {

         void run( ) { }

解析:接口是用來實現的,不是繼承,所以AB兩個選項錯誤。

      根據Java多態機制,子類可以為父類(接口)實例化對象

      根據子類實現接口的規則,子類必須重寫接口當中的抽象方法

      此時又復習到了方法重寫的規則:子類重寫的方法它的權限必須

      大於等於父類方法權限(除去private外)。根據以上得出C是對的

 

 

4.

當線程調用start( )后,其所處狀態為( C   )。(選擇一項)

 

 

 

 

A

阻塞狀態

 

B.

運行狀態

 

C.

就緒狀態

 

D.

新建狀態

解析:線程的五個狀態也就是它的生命周期:

新建狀態----通過new關鍵字來創建線程對象

就緒狀態----調用start()方法

運行狀態----調用run()方法

阻塞狀態----調用sleep()、wait()、join() 、yield()、interrupt ()等方法

消亡狀態----調用stop()方法,但是此方法已經過時。

 

 

5.

下列關於Thread類提供的線程控制方法的說法中,錯誤的是(  C  )。(選擇一項)

 

 

 

 

A

線程A中執行線程B的join()方法,則線程A等待直到B執行完成

 

B.

線程A通過調用interrupt()方法來中斷其阻塞狀態

 

C.

若線程A調用方法isAlive()返回值為false,則說明A正在執行中,也可能是可運行狀態

 

D.

currentThread()方法返回當前線程的引用

解析:

A: join()方法—強制加入,加入的線程執行完畢之后才能執行其他線程

B:interrupt()方法---線程中斷,題中的說法有些牽強

C:isAlive()方法---判斷一個線程是否在活動,如果在活動返回真,反之假

D:currentThread()方法返回正在執行的線程

從以上得知,C明顯錯誤。

 

6.

下列關於線程的優先級說法中,正確的是(  BD  )。(選擇兩項)

 

 

 

 

A

線程的優先級是不能改變的

 

B.

線程的優先級是在創建線程時設置的

 

C.

在創建線程后的任何時候都可以重新設置

 

D.

線程的優先級的范圍在1-10之間

       解析:線程的優先級可以通過setPriority(int newPriority)的方法進行設置

             線程一共有三個優先級,分別是:最低優先級(1中等優先級(5

             最高優先級(10),咱們經常寫的main方法就是中等優先級線程。

             A:線程的優先級是可以更改也可以獲取,但是有一點,即使設置為最高

                優先級也不一定先執行,只是它優先執行的幾率比較高。

             B:線程的優先級是在創建時進行設置,通過setPriority()方法設置

           C:正在執行的線程是不允許重新設置線程優先級的。

D:線程的優先級范圍是1—10 符合要求

 

7.

以下選項中關於Java中線程控制方法的說法正確的是(  AD   )。(選擇二項)

 

 

 

 

A.

join ( ) 的作用是阻塞指定線程等到另一個線程完成以后再繼續執行

 

B.

sleep ( ) 的作用是讓當前正在執行線程暫停,線程將轉入就緒狀態

 

C.

yield ( ) 的作用是使線程停止運行一段時間,將處於阻塞狀態

 

D.

setDaemon( )的作用是將指定的線程設置成后台線程

解析:

A:join()方法—線程的強制加入,加入的線程執行完畢之后再執行其他線程

B:sleep()方法—線程休眠,等時間過時,線程處於運行狀態

C:yield()方法—線程禮讓,讓出CUP資源,其他線程先執行,有些與join()

                方法類似

D:setDaemon()方法--將指定的線程設置成后台線程,對的。

題的答案是:AD,但是個人感覺C選項也是對的……

 

8.

在多個線程訪問同一個資源時,可以使用(  A  關鍵字來實現線程同步,保證對資源安全訪問。(選擇一項)

 

 

 

 

A.

Synchronized

 

B.

Transient

 

C.

Static

 

D.

Yield

         解析:關於同步,有兩種實現方式,一種是同步方法,一種是同步代碼塊

                無論怎樣,都需要使用到synchronized關鍵字。

                同步方法:

                     權限修飾符  synchronized  返回值類型  方法名稱(參數列表){

                     N行代碼;

}

            同步代碼塊:

                 Synchronized(對象){

                     N行代碼;

}

9.

Java中線程安全問題是通過關鍵字(   C  )解決的?。(選擇一項)

 

 

 

 

A.

Finally

 

B.

wait( )

 

C.

Synchronized

 

D.

notify( )

10.

以下說法中關於線程通信的說法錯誤的是(  D  ?。(選擇一項)

 

 

 

 

A.

可以調用wait()、notify()、notifyAll()三個方法實現線程通信

 

B.

wait()、notify()、notifyAll()必須在synchronized方法或者代碼塊中使用

 

C.

wait()有多個重載的方法,可以指定等待的時間

 

D.

wait()、notify()、notifyAll()是Object類提供的方法,子類可以重寫

解析:

A選項:

在線程通信中,可以調用wait()、notify()、notifyAll()三個方法實現線程通信,這三個方法都是Object類提供的public方法,所以任何類都具有這三個方法。

B選項:在編程題的第二題當中,wait()方法、notify()方法、notifyAll()方法都是寫在同步方法當中,具體可以查看此類的源碼。

C選項:Object類當中的wait方法的重載如下:

public final void wait()

public final void wait(long timeout)
public final void wait(long timeout, int nanos)
三個方法都拋出異常-- InterruptedException
   D選項 : 看A選項的解釋
    以上三個方法都使用final修飾,所以子類是不能重寫的

 

三、    判斷題

  1. 進程是線程Thread內部的一個執行單元,它是程序中一個單一順序控制流程。( ×  )

解析:線程是進程的一個執行單位,進程包含線程。

  1. Thread類實現了Runnable接口。(   √  )

解析:Thread類在JDK當中的定義如下:

         Public class Thread extends Object  implements Runnable

        從定義可知,它是Runnable接口的子類。

  1. 一個進程可以包括多個線程。兩者的一個主要區別是:線程是資源分配的單位,而進程CPU調度和執行的單位。(  ×  )

解析:不管是進程還是線程,都是通過循環獲得自己執行的時間片,獲得CUP資源。

  1. 用new關鍵字建立一個線程對象后,該線程對象就處於新生狀態。處於新生狀態的線程有自己的內存空間,通過調用start進入就緒狀態。(  √  )

解析:具體解析看選擇題第四題的解釋。

  1. A線程的優先級是10,B線程的優先級是1,那么當進行調度時一定會先調用A( ×  )

解析:線程的執行,不是誰的優先級高就先執行,只是它的概率會高。

  1. 線程可以用yield使低優先級的線程運行。(  ×  )

解析:yield()方法是線程禮讓,可以讓出自己執行其他線程,由於線程的執行存在嚴重

     的隨機性,不能確定使低優先級的線程執行。

  1. Thread.sleep( )方法調用后,當等待時間未到,該線程所處狀態為阻塞狀態。當等待時間已到,該線程所處狀態為運行狀態。( √   )

解析:sleep()方法是線程休眠,處於阻塞狀態,當時間一到,就會執行處於運行狀態。

      如果真要追究用詞的嚴謹性,應該不是”等待時間”,而是”休眠時間”。

  1. 當一個線程進入一個對象的一個synchronized方法后,其它線程不可以再進入該對象同步的其它方法執行。(  √  )

解析:對的,可以查看一下編程題第二題的源碼。

  1. wait方法被調用時,所在線程是會釋放所持有的鎖資源, sleep方法不會釋放。( √  )

解析:sleep 是線程類(Thread)的方法,導致此線程暫停執行指定時間,給執行機會給其他線程,但是監控狀態依然保持,到時后會自動恢復,所以調用sleep 不會釋放對象鎖。
wait 是Object 類的方法,對此對象調用wait 方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發出notify 方法(或notifyAll)后本線程才進入對象鎖定池准備獲得對象鎖進入運行狀態。

  1. wait、notify、notifyAll是在Object類中定義的方法。( √  )

解析:具體可以查看API幫助文檔,查看。

  1. notify是喚醒所在對象wait pool中的第一個線程。( ×  )

解析:喚醒的不一定是第一個線程。

      JDK已經明確說明喚醒哪個thread是隨意決定的,沒有特定順序
The choice is arbitrary and occurs at the discretion of the implementation

 

四、    簡答題

  1. 簡述程序、進程和線程的聯系和區別。
  2. 創建線程的兩種方式分別是什么?各有什么優缺點。
  3. sleep、yield、join方法的區別?
  4. synchronize修飾的語句塊,如下面的代碼。是表示該代碼塊運行時必須獲得account對象的鎖。如果沒有獲得,會有什么情況發生?

synchronized (account) {

         if(account.money-drawingNum<0){

                   return;

         }

}

 

  1. 請你簡述sleep( )和wait( )有什么區別?
  2. 死鎖是怎么造成的?用文字表達。再寫一個代碼示例。
  3. Java中實現線程通信的三個方法及其作用。
  4. 為什么不推薦使用stop和destroy方法來結束線程的運行?

 

五、    編碼題

1.設計一個多線程的程序如下:設計一個火車售票模擬程序。假如火車站要有100張火車票要賣出,現在有5個售票點同時售票,用5個線程模擬這5個售票點的售票情況。

 1 public class CharPrint extends Thread  2 {  3     // 定義屬性
 4     private Printer p;  5     //構造方法
 6     public CharPrint(Printer p)  7  {  8         super();  9         this.p = p;  10  }  11     //重寫run()方法
 12     public void run()  13  {  14         char c = 'A';//定義起始位置  15         //通過for循環對其進行輸出
 16         while (c <= 'Z')  17  {  18  p.print(c);  19             c++;//控制while循環當中的條件表達式
 20  }  21  }  22 }  23 public class NumberPrint extends Thread  24 {  25     //定義屬性
 26     private Printer p;  27     //構造方法
 28     public NumberPrint(Printer p)  29  {  30         this.p = p;  31  }  32     //重寫run()方法
 33     public void run()  34  {  35         int i = 1;//定義起始位置
 36         while (i <= 52)  37  {  38  p.print(i);  39             i++;//控制while循環當中的條件表達式
 40  }  41  }  42 }  43 public class Printer  44 {  45     //定義一個int類型變量---用於計數
 46     int index = 1;  47     //同步的方法---print()
 48     public synchronized void print(int i)  49  {  50         //判斷是否是3的倍數
 51         while (index % 3 == 0)  52  {  53             try
 54  {  55                 wait();//線程等待
 56             } catch (InterruptedException e)  57  {  58                 // TODO Auto-generated catch block
 59  e.printStackTrace();  60  }  61  }  62         //打印輸出數字
 63         System.out.print("" + i);  64         //控制while循環中的條件表達式
 65         index++;  66         //線程喚醒
 67  notifyAll();  68  }  69     public synchronized void print(char c)  70  {  71         //判斷是否是3的倍數
 72         while (index % 3 != 0)  73  {  74             try
 75  {  76  wait();  77             } catch (InterruptedException e)  78  {  79                 // TODO Auto-generated catch block
 80  e.printStackTrace();  81  }  82  }  83         //打印字母
 84         System.out.print("" + c);  85         //控制while循環中的條件表達式
 86         index++;  87         //喚醒線程
 88  notifyAll();  89  }  90 }  91 public class Test  92 {  93     public static void main(String[] args)  94  {  95         //創建Printer對象,為NumberPrint()類構造方法做准備
 96         Printer p = new Printer();  97         //創建線程---子類為父類實例化對象
 98         Thread t1 = new NumberPrint(p);  99         Thread t2 = new CharPrint(p); 100         //啟動線程
101  t1.start(); 102  t2.start(); 103  } 104 }

2.編寫兩個線程,一個線程打印1-52的整數,另一個線程打印字母A-Z。打印順序為12A34B56C….5152Z。即按照整數和字母的順序從小到大打印,並且每打印兩個整數后,打印一個字母,交替循環打印,直到打印到整數52和字母Z結束。

要求:

1)         編寫打印類Printer,聲明私有屬性index,初始值為1,用來表示是第幾次打印。

2)         在打印類Printer中編寫打印數字的方法print(int i),3的倍數就使用wait()方法等待,否則就輸出i,使用notifyAll()進行喚醒其它線程。

3)         在打印類Printer中編寫打印字母的方法print(char c),不是3的倍數就等待,否則就打印輸出字母c,使用notifyAll()進行喚醒其它線程。

4)         編寫打印數字的線程NumberPrinter繼承Thread類,聲明私有屬性private Printer p;在構造方法中進行賦值,實現父類的run方法,調用Printer類中的輸出數字的方法。

5)         編寫打印字母的線程LetterPrinter繼承Thread類,聲明私有屬性private Printer p;在構造方法中進行賦值,實現父類的run方法,調用Printer類中的輸出字母的方法。

6)         編寫測試類Test,創建打印類對象,創建兩個線程類對象,啟動線程。

 

 1 public class TicketSalSystem implements Runnable  2 {  3     // 定義變量---票數/票號
 4     public int ticket = 100;  5     public int count = 0;  6     // 重寫run()方法
 7     public void run()  8  {  9         // 定義while循環, 循環售票
10         while (ticket > 0) 11  { 12             // 根據題的要求,實現同步,此時定義同步代碼塊
13             synchronized (this) 14             {// 傳入對象,使用this代替當前類對象 15                 // 判斷是否還有票,如果大於零說明還有票可賣
16                 if (ticket > 0) 17  { 18                     // 線程休眠0.5秒
19                     try
20  { 21                         Thread.sleep(500); 22                     } catch (InterruptedException e) 23  { 24  e.printStackTrace(); 25  } 26                     count++; // 票號++
27                     ticket--;// 循環售票,賣一張少一張 28                     // 輸出當前的售票窗口和票號
29  System.out.println(Thread.currentThread().getName() 30                             + "\t當前票號:" + count); 31  } 32  } 33  } 34  } 35 } 36 public class TicketTest 37 { 38     public static void main(String[] args) 39  { 40         // 創建線程類對象
41         TicketSalSystem st = new TicketSalSystem(); 42         // 啟動5次線程
43         for (char i = 'A'; i <= 'F'; i++) 44  { 45             /*
46  * 創建匿名Thread類對象 47  * 1、根據Thread類構造方法,傳入Runnable接口對象 48  * TicketSalSystem類是Runnable接口的子類,子類對象st可以讓父類接收 49  * 2、Thread類的構造方法如下: 50  * public Thread(Runnable run,String name) 51  * 在創建線程的同時,為線程名稱 52  * 3、啟動線程是使用start方法,啟動之后JVM會默認的區調用run()方法 53              */
54             new Thread(st, "售票口" + i).start(); 55  } 56  } 57 }

六、    可選題

1.設計4個線程,其中兩個線程每次對j增加1,另外兩個線程對j每次減少1。

要求:使用內部類實現線程,對j增減的時候不考慮順序問題。

 

 1 public class ThreadTest61  2 {  3     //聲明成員變量j
 4     private int j;  5     public static void main(String[] args)  6  {  7         //創建ThreadTest61的對象
 8         ThreadTest61 tt = new ThreadTest61();  9         //創建內部線程類對象
10         Inc inc = tt.new Inc(); 11         Dec dec = tt.new Dec(); 12         for (int i = 0; i < 2; i++) 13  { 14             // 創建線程對象,啟動線程
15             Thread t = new Thread(inc); 16  t.start(); 17             // 創建線程對象,啟動線程
18             t = new Thread(dec); 19  t.start(); 20  } 21  } 22     //實現同步對j的值加
23     private synchronized void inc() 24  { 25         //調用此方法一次,對j就增加一次
26         j++; 27         System.out.println(Thread.currentThread().getName() + "-inc:" + j); 28  } 29     //實現同步對j的值減
30     private synchronized void dec() 31  { 32         //調用此方法一次,對j就減一次
33         j--; 34         System.out.println(Thread.currentThread().getName() + "-dec:" + j); 35  } 36     //內部類實現Runnable接口,重寫run()方法
37     class Inc implements Runnable 38  { 39         public void run() 40  { 41             //for循環當中調用inc()方法,實現每次對j加1
42             for (int i = 0; i < 100; i++) 43  { 44                 //調用加的方法
45  inc(); 46  } 47  } 48  } 49     //內部類實現Runnable接口,重寫run()方法
50     class Dec implements Runnable 51  { 52         public void run() 53  { 54             //for循環當中調用inc()方法,實現每次對j減1
55             for (int i = 0; i < 100; i++) 56  { 57                 //調用減的方法
58  dec(); 59  } 60  } 61  } 62 }

2.編寫多線程程序,模擬多個人通過一個山洞的模擬。這個山洞每次只能通過一個人,每個人通過山洞的時間為5秒,有10個人同時准備過此山洞,顯示每次通過山洞人的姓名和順序。

 1 public class ThreadTest62  2 {  3     public static void main(String[] args)  4  {  5         /*創建一個山洞對象,為Thread類構造方法做准備  6  * public Thread(Runnable run,String name)  7          */
 8         Tunnel tul = new Tunnel();  9         //創建十個過山洞線程,並為線程命名
10         Thread p1 = new Thread(tul, "p1"); 11         Thread p2 = new Thread(tul, "p2"); 12         Thread p3 = new Thread(tul, "p3"); 13         Thread p4 = new Thread(tul, "p4"); 14         Thread p5 = new Thread(tul, "p5"); 15         Thread p6 = new Thread(tul, "p6"); 16         Thread p7 = new Thread(tul, "p7"); 17         Thread p8 = new Thread(tul, "p8"); 18         Thread p9 = new Thread(tul, "p9"); 19         Thread p10 = new Thread(tul, "p10"); 20         //啟動十個線程
21  p1.start(); 22  p2.start(); 23  p3.start(); 24  p4.start(); 25  p5.start(); 26  p6.start(); 27  p7.start(); 28  p8.start(); 29  p9.start(); 30  p10.start(); 31  } 32 } 33 //創建山洞類並實現Runnable接口,重寫run()方法
34 class Tunnel implements Runnable 35 { 36     //定義變量,初始化過山洞人數
37     int crossedNum = 0; 38     //重寫run()方法,在此方法當中調用cross()方法
39     public void run() 40  { 41  cross(); 42  } 43     //定義過山洞的同步方法
44     public synchronized void cross() 45  { 46         //每個人通過山洞的時間為5秒
47         try
48  { 49             Thread.sleep(5000); 50         } catch (InterruptedException e) 51  { 52  e.printStackTrace(); 53  } 54         //人數統計,過一個人增加一個人
55         crossedNum++; 56         //顯示每次通過山洞人的姓名
57  System.out.println(Thread.currentThread().getName() 58                 + "通過了山洞,這是第" + crossedNum + "個用戶"); 59  } 60 }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM