<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 一、概述 世間萬物都可以同時完成很多工作。例如,人體可以同時進行呼吸、血液循環、思考問題等活動。用戶既可以使用計算機聽歌,也可以編寫文檔和發送郵件,而這些活動的完成可以同時進行。這種同時執行多個操作的“思想”在 Java 中被稱為并發,而將并發完成的每一件事稱為線程。 在 Java 中,并發機制非常重要,但并不是所有程序語言都支持線程。在以往的程序中,多以一個任務完成以后再進行下一個任務的模式進行,這樣下一個任務的開始必須等待前一個任務的結束。Java 語言提供了并發機制,允許開發人員在程序中執行多個線程,每個線程完成一個功能,并與其他線程并發執行。這種機制被稱為多線程。 > Windows 系統是多任務操作系統,它以進程為單位。一個進程是一個包含有自身地址的程序,每個獨立執行的程序都稱為進程,也就是正在執行的程序。 > 系統可以分配給每個進程一段有限的執行 CPU 的時間(也稱為 CPU 時間片),CPU 在這段時間中執行某個進程,然后下一個時間段又跳到另一個進程中去執行。由于 CPU 切換的速度非常快,給使用者的感受就是這些任務似乎在同時運行,所以使用多線程技術后,可以在同一時間內運行更多不同種類的任務。 線程可以理解成是在進程中獨立運行的子任務。比如,QQ.exe 運行時就有很多的子任務在同時運行。像好友視頻、下載文件、傳輸數據、發送表情等,這些不同的任務或者說功能都可以同時運行,其中每一項任務完全可以理解成是“線程”在工作,傳文件、聽音樂、發送圖片表情等功能都有對應的線程在后臺默默地運行。 ## 二、線程的創建 ### 2.1 通過 Thread 類創建線程 ``` public class MyThread extends Thread { public void run() { System.out.println(getName() + " 線程正在運行"); } } ``` 當一個類繼承 Thread 類后,就可以在該類中覆蓋 run() 方法,將實現線程功能的代碼寫入 run() 方法中,然后調用 Thread 類的 start() 方法啟動線程。 ``` public class ThreadTest { public static void main(String[] args) { System.out.println("主線程開始運行"); Thread thread = new MyThread(); thread.start(); // thread.run(); System.out.println("主線程運行結束"); } } ``` > 如果 start() 方法調用一個已經啟動的線程,系統將會拋出 IllegalThreadStateException 異常。 ``` 主線程開始運行 主線程運行結束 Thread-0 線程正在運行 ``` MyThread 類中的 start() 方法通知“線程規劃器”此線程已經準備就緒,等待調用線程對象的 run() 方法。這個過程其實就是讓系統安排一個時間來調用 Thread 中的 run() 方法,也就是使線程得到運行,啟動線程,具有異步執行的效果。 ``` 主線程開始運行 Thread-0 線程正在運行 主線程運行結束 ``` 如果調用代碼 thread.run() 就不是異步執行了,而是同步,那么此線程對象并不交給“線程規劃器”來進行處理,而是由 main 主線程來調用 run() 方法,也就是必須等 run() 方法中的代碼執行完后才可以執行后面的代碼。 ``` public class MyThread extends Thread { public MyThread() {} public MyThread(String name) { super(name); } public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + " 線程運行第" + i + "次"); } } } public class ThreadTest { public static void main(String[] args) { System.out.println("主線程開始運行"); MyThread mt = new MyThread("myThread"); t.start(); for (int i = 0; i < 100; i++) { System.out.println("主線程運行第" + i + "次"); } System.out.println("主線程運行結束"); } } ``` 從上面的運行結果來看,MyThread 類中 run() 方法執行的時間要比主線程晚。這也說明在使用多線程技術時,代碼的運行結果與代碼執行順序或調用順序是無關的。同時也驗證了線程是一個子任務,CPU 以不確定的方式,或者說以隨機的時間來調用線程中的 run() 方法。 ``` public class MyThread extends Thread { private int i; public MyThread3(int i) { super(); this.i = i; } public void run() { System.out.println("當前數字:" + i); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { MyThread m = new MyThread(i); m.start(); } } } ``` 從運行結果中可以看到,雖然調用時數字是有序的,但是由于線程執行的隨機性,導致輸出的數字是無序的,而且每次順序都不一樣。除了異步調用之外,同步執行線程 start() 方法的順序不代表線程啟動的順序。 ***** 【選擇】下列選項中,哪兩句的說法是錯誤的()(選擇兩項) ``` A 線程是比進程還要小的運行單位 B Thread 類位于 java.thread 包下 C run() 方法用于啟動線程 D CPU 使用時間片輪轉的工作方法,可以讓多個程序輪流占用 CPU,達到同時運行的效果 ``` 【閱讀】以下代碼中,在(1)處加入哪條語句能成功啟動線程() ``` public class ThreadOne extends Thread { public void run() { System.out.println("執行 ThreadOne 進程"); } } public class ThreadTest { public static void main(String[] args) { ThreadOne one = new ThreadOne(); // (1) } } ``` 【選擇】通過 Thread 類創建線程時要()(選擇三項) ``` A 繼承 Thread 類 B 在子類中重寫 run() 方法 C 實現 Runnable 接口 D 調用 start() 方法啟動線程 ``` 【編程】通過繼承 Thread 類的方式創建線程,并在線程體中通過循環打印輸出如演示所示的內容。 ``` 打印機正在打印1 打印機正在打印2 打印機正在打印3 打印機正在打印4 打印機正在打印5 打印機正在打印6 打印機正在打印7 打印機正在打印8 打印機正在打印9 打印機正在打印10 ``` ### 2.2 實現 Runnable 接口創建線程 如果要創建的線程類已經有一個父類,這時就不能再繼承 Thread 類,因為 Java 不支持多繼承,所以可以通過實現 Runnable 接口來應對這樣的情況。 > 從 JDK 的 API 中可以發現,實質上 Thread 類實現了 Runnable 接口,其中的 run() 方法正是對 Runnable 接口中 run() 方法的具體實現。 實現 Runnable 接口的程序會創建一個 Thread 對象,并將 Runnable 對象與 Thread 對象相關聯。Thread 類有如下兩個與 Runnable 有關的構造方法: ``` 1. public Thread(Runnable r) 2. public Thread(Runnable r, String name) ``` 使用 Runnable 接口啟動線程的基本步驟如下: ``` 1. 創建一個 Runnable 對象。 2. 使用參數帶 Runnable 對象的構造方法創建 Thread 實例。 3. 調用 start() 方法啟動線程。 ``` :-: ![](http://cndpic.dodoke.com/388b7c911f81a97a6a99cf510e1a08a7) 【例題】案例演示如何實現 Runnable 接口,以及如何啟動線程。 ``` public class MyRunnable implements Runnable { public void run() { System.out.println(Thread.currentThread().getName() + "運行中!"); } public static void main(String[] args) { Runnable rn = new MyRunnable(); Thread th1 = new Thread(rn); th1.start(); Thread th2 = new Thread(rn); th2.start(); } } ``` ``` public class MyRunnable implements Runnable { int i = 0; // 此時多個線程共用一個成員變量 public void run() { while(i < 10) { System.out.println(Thread.currentThread().getName() + "運行第" + (i++) + "次"); } } public static void main(String[] args) { Runnable rn = new MyRunnable(); Thread th1 = new Thread(rn); th1.start(); Thread th2 = new Thread(rn); th2.start(); } } ``` ***** 【選擇】用 Runnable 接口創建線程的主要工作如下,它們正確的先后順序為()(選擇一項) ``` 1) 通過實現類的對象創建線程類的對象 2) 聲明實現 Runnable 接口的類 3) 調用 start() 方法啟動線程 4) 創建實現類的對象 5) 在實現類內實現 run() 方法 ``` ``` A 1-4-2-5-3 B 2-1-4-5-3 C 2-5-4-1-3 D 1-5-2-4-3 ``` 【編程】編寫代碼完成以下任務: 1. 通過實現 Runnable 接口的方式創建線程類 Cat 和 Dog,run() 方法實現的功能為:加入一個循環長度為3的循環,分別循環輸出信息`A cat`和`A dog`。 2. 在測試類中分別創建 Cat 和 Dog 類的對象,啟動兩個線程。 3. 在測試類中創建一個循環長度為3的for循環,打印輸出信息`main thread`。 ``` main thread main thread main thread Thread-1A dog Thread-1A dog Thread-1A dog Thread-0A cat Thread-0A cat Thread-0A cat ``` ## 三、線程的生命周期 ### 3.1 線程的狀態和生命周期 線程具有生命周期,主要包括 7 種狀態,分別是出生狀態、就緒狀態、運行狀態、等待狀態、休眠狀態、阻塞狀態和死亡狀態。 1. 出生狀態:用戶在創建線程時所處的狀態,在用戶使用該線程實例調用`start()`方法之前,線程都處于出生狀態。 2. 就緒狀態:也稱可執行狀態,當用戶調用`start()`方法之后,線程處于就緒狀態。 3. 運行狀態:當線程得到系統資源后進入運行狀態。 4. 等待狀態:當處于運行狀態下的線程調用 Thread 類的`wait()`方法時,該線程就會進入等待狀態。進入等待狀態的線程必須調用 Thread 類的`notify()`方法才能被喚醒。`notifyAll()`方法是將所有處于等待狀態下的線程喚醒。 5. 休眠狀態:當線程調用 Thread 類中的`sleep()`方法時,則會進入休眠狀態。 6. 阻塞狀態:如果一個線程在運行狀態下發出輸入/輸出請求,該線程將進入阻塞狀態,在其等待輸入/輸出結束時,線程進入就緒狀態。對阻塞的線程來說,即使系統資源關閉,線程依然不能回到運行狀態。 7. 死亡狀態:當線程的`run()`方法執行完畢,線程進入死亡狀態。 > 提示:一旦線程進入可執行狀態,它會在就緒狀態與運行狀態下輾轉,同時也可能進入等待狀態、休眠狀態、阻塞狀態或死亡狀態。 ***** 【選擇】關于線程的狀態和生命周期的說法,正確的是()(選擇兩項) ``` A 只有獲取到 CPU 的使用權,線程才能從可運行狀態轉為運行狀態 B 調用 start() 方法可以使線程處于可運行狀態 C 如果正在運行的線程異常終止,則線程會處于阻塞狀態 D 一個正在運行的線程,調用 join() 方法,則會處于終止狀態 ``` ### 3.2 sleep 方法的使用 ``` public static void sleep(long millis) { ... } ``` * 指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)。 * 這個正在執行的線程是指 Thread.currentThread() 返回的線程。 * 參數為休眠的時間,單位是毫秒。 ``` public class MyRunnable implements Runnable { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "運行第" + i + "次"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class SleepTest { public static void main(String[] args) { Runnable r = new MyRunnable(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } ``` ***** 【選擇】以下說法錯誤的是()(選擇一項) ``` A sleep() 方法的參數是以毫秒為單位的 B 使用實現 Runnable 接口的方式創建線程,一定要重寫 run 方法 C 當創建線程對象,線程即進入創建狀態 D 調用 sleep 方法時,不需要處理異常 ``` 【閱讀】關于下列代碼,說法正確的是() ``` public class MyRunnable implements Runnable { public void run() { for (int i = 0; i < 3; i++) { System.out.println("正在運行" + i); Thread.sleep(500); } } } public class Test { public static void main(String[] args) { Runnable m = new MyRunnable(); Thread th = new Thread(m); th.start(); } } ``` 【編程】利用線程輸出`a~z`的26個字母(橫向輸出),要求每隔一秒鐘輸出一個字母。 ``` abcdefghijklmnopqrstuvwxyz ``` ### 3.3 join 方法的使用 ``` 1. public final void join() 等待調用該方法的線程結束后才能執行。 2. public final void join(long millis) 等待該線程終止的最長時間為 millis 毫秒。 ``` ``` public class MyRunnable implements Runnable { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "正在執行第" + i + "次"); } } } public class JoinTest { public static void main(String[] args) { Runnable r = new MyRunnable(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); try { t1.join(); } catch(InterruptedException e) { e.printStackTrace(); } t2.start(); } } ``` ***** 【選擇】下列關于 Thread 類中的 join() 方法說法錯誤的是()(選擇兩項) ``` A 調用 join() 方法可以使其他線程由正在運行狀態變成阻塞狀態 B join() 方法可以通過 Thread 類名直接訪問 C 子類中可以重寫 join() 方法 D join() 方法的作用是等待調用該方法的線程結束后才能執行 ``` ### 3.4 線程的優先級 > Java 為線程類提供了10個優先級,優先級可以用整數1~10表示,超過范圍會拋出異常。主線程優先級的默認值為 5。 * 優先級常量 ``` MAX_PRIORITY:線程的最高優先級 10 MIN_PRIORITY:線程的最低優先級 1 NORM_PRIORITY:線程的默認優先級 5 ``` * 使用 Thread 類中的 setPriority() 方法來設置線程的優先級。語法如下: ``` public final void setPriority(int newPriority); ``` * 使用 Thread 類中的 getPriority() 方法來獲取線程的優先級。語法如下: ``` public final int getPriority(); ``` ``` public class MyRunnable implements Runnable { public void run() { System.out.println("優先級為" + Thread.currentThread().getPriority()); for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "正在運行" + i + "次"); } } public static void main(String[] args) { int mainPriority = Thread.currentThread().getPriority(); // 獲取主線程的優先級 System.out.println("主線程的優先級為" + mainPriority); Runnable r = new MyRunnable(); Thread t1 = new Thread(r, "線程1"); Thread t2 = new Thread(r, "線程2"); t1.setPriority(10); t2.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); } } ``` ***** 【選擇】下列說法正確的是()(選擇一項) ``` A 設置優先級的方法為 public int setPriority(int n) B 優先級可用1-10的整數表示 C 獲取優先級的方法是 public void getPriorty() D 在 Java 中,優先級高的線程一定會比優先級低的線程先運行 ``` ## 四、線程同步 * 各個線程是通過競爭 CPU 時間而獲得運行機會的 * 各個線程什么時候得到 CPU 時間,占用多久,是不可預測的 * 一個正在運行著的線程在什么地方被暫停是不確定的 ``` public class Bank { private int balance; public Bank(int balance) { this.balance = balance; } // getter setter ... @Override public String toString() { return "Bank{balance=" + balance + "}"; } // 存款 public void saveBalance(int value) { // 獲取當前的賬號余額 int balance = getBalance(); try { Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrace(); } setBalance(balance + value); // 輸出存款后的賬戶余額 System.out.println("存款后的賬戶余額為" + getBalance()); } // 取款 public void drawBalance(int value) { int balance = getBalance(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(balance - value); System.out.println("取款后的賬戶余額為" + getBalance()); } } public class SaveBalance implements Runnable { Bank bank; public SaveBalance(Bank bank) { this.bank = bank; } public void run() { bank.saveBalance(100); } } public class DrawBalance implements Runnable { Bank bank; public DrawBalance(Bank bank) { this.bank = bank; } public void run() { bank.drawBalance(200); } } public class BankTest { public static void main(String[] args) { Bank bank = new Bank(1000); Runnable sb = new SaveBalance(bank); Runnable db = new DrawBalance(bank); Thread save = new Thread(sb); Thread draw = new Thread(db); save.start(); draw.start(); try { save.join(); draw.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank); } } ``` 為了處理共享資源競爭,可以使用同步機制。所謂同步機制,指的是兩個線程同時作用在一個對象上,應該保持對象數據的統一性和整體性。[](http://c.biancheng.net/java/)Java 提供 synchronized 關鍵字,為防止資源沖突提供了內置支持。 * 在一個類中,用 synchronized 關鍵字聲明的方法為同步方法。格式如下: ~~~ public [static] synchronized 類型名稱 方法名稱() { ... } ~~~ * synchronized 也可以作用于代碼塊。對于同步塊,synchronized 獲取的是參數中的對象鎖。格式如下: ``` synchronized(obj) { ... } ``` Java 有一個專門負責管理線程對象中同步方法訪問的工具——同步模型監視器,它的原理是為每個具有同步代碼的對象準備唯一的一把“鎖”。當多個線程訪問對象時,只有取得鎖的線程才能進入同步方法,其他訪問共享對象的線程停留在對象中等待。 ``` public synchronized void saveBalance(int value) { ... } public void drawBalance(int value) { synchronized(this) { ... } } ``` ***** 【選擇】運行下列代碼,結果是()(選擇兩項) ``` // Barber(理發師) 類 public class Barber { public void wash() { synchronized(this) { System.out.println("打濕頭發"); System.out.println("洗頭水"); System.out.println("沖洗"); } } public synchronized void cut() { System.out.println("剪短"); System.out.println("燙發"); } } public class Cut extends Thread { Barber b; public Cut(Barber b) { this.b = b; } public void run() { b.cut(); } } public class Wash extends Thread { Barber b; public Wash(Barber b) { this.b = b; } public void run() { b.wash(); } } public class Test { public static void main(String[] args) { Barber b = new Barber(); Cut cut = new Cut(b); Wash wash = new Wash(b); cut.start(); wash.start(); } } ``` ``` A 剪短 打濕頭發 燙頭 洗頭水 沖洗 B 剪短 燙發 打濕頭發 洗頭水 沖洗 C 打濕頭發 洗頭水 沖洗 剪短 燙發 D 剪短 打濕頭發 洗頭水 沖洗 燙發 ``` 【選擇】下列對關鍵字 synchronized 說法不正確的是()(選擇一項) ``` A synchronized(同步),即協調不同線程之間的工作 B synchronized 關鍵字可以用在成員方法中 C 保證多個線程可以同時執行和結束 D 保證共享對象在同一時刻只能被一個線程訪問 ``` ## 五、線程間通信 ``` wait(): 中斷方法的執行,使線程等待 notify(): 喚醒處于等待的某一個線程,使其結束等待 notifyAll(): 喚醒所有處于等待的線程,使他們結束等待 ``` ``` public class Count { private int n; boolean flag = false; public synchronized int getN() throws InterruptedException{ if (!flag) wait(); System.out.println("消費:" + n); flag = false; notifyAll(); return n; } public synchronized void setN(int n) throws InterruptedException { if (flag) wait(); System.out.println("生產:" + n); this.n = n; flag = true; notifyAll(); } } public class Producer implements Runnable { private Count count; public Producer(Count count) { this.count = count; } public void run() { int i = 0; while (true) { try { count.setN(i++); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Consumer implements Runnable { private Count count; public Consumer(Count count) { this.count = count; } public void run() { while (true) { try { count.getN(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class CountTest { public static void main(String[] args) { Count count = new Count(); new Thread(new Producer(count)).start(); new Thread(new Consumer(count)).start(); } } ``` ***** 【選擇】以下說法錯誤的是()(選擇一項) ``` A wait() 方法用于使線程等待 B notify() 方法用于喚醒一個線程 C notifyAll() 方法用于喚醒多個線程 D 使用 wait() 方法阻塞的線程,可以不用喚醒 ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看