<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 03 多線程開發如此簡單—Java中如何編寫多線程程序 > 學習這件事不在乎有沒有人教你,最重要的是在于你自己有沒有覺悟和恒心。 > —— 法布爾 ## 1\. Java 實現多線程的方式 前文介紹了多線程的各種應用場景,你是不是已經磨刀霍霍,迫不及待想進入 java 多線程的世界里了?別急,我們第一步要先得到進入多線程世界的鑰匙,也就是如何在 java 中實現多線程。 在 java 中實現多線程有四種方式,如下: 1. 繼承 Thread 類 2. 實現 Runnable 接口 3. 使用 FutureTask 4. 使用 Executor 框架 其中繼承 Thread 類和實現 Runnable 接口是最基本的方式,但有一個共同的缺點 ---- 沒有返回值。而 FutureTask 則解決了這個問題,后面會單獨講解。Executor 是 JDK 提供的多線程框架,功能十分強大,后面也會有章節專門講解。本篇文章主要介紹前兩種最基本的方式,目的是讓你對多線程編程有初步的認識,帶你打開多線程編程的大門。 前文我說過,無形的軟件,都來自于有形的現實世界。我們在學習多線程的過程中,時刻以現實世界作為參照,理解起來就會容易很多。我們設想這樣一個生活中的場景,看看程序如何實現。 小明是一位學生,今天不太開心。因為昨天英語課學習了一個新的單詞,今天考試時他寫錯了。老師懲罰他抄寫 100 遍。這個單詞有點長,是什么單詞呢?internationalization。看著眼熟嗎?做過國際化開發的同學一定認識,這個單詞因為太長,在 java 中被稱為 i18n,也就是首字母 i 和尾字母 n 之間有 18 個字母。小明很苦惱,怎么能快點寫完呢? ![圖片描述](https://img1.sycdn.imooc.com/5d7238b90001c68008760558.jpg) ## 2\. 單線程實現單詞抄寫 OK,下面我們通過程序來模擬小明抄寫單詞的任務。我們編寫如下幾個類: 1、Punishment.java 存儲要抄寫的單詞,以及剩余的抄寫次數。主要代碼如下: ~~~java public class Punishment { private int leftCopyCount; private String wordToCopy; } ~~~ 2、Student.java 持有 Punishment 的引用。實現了抄寫單詞的 copyWord 方法。主要代碼如下: ~~~java public class Student { private String name; private Punishment punishment; public Student(String name,Punishment punishment) { this.name=name; this.punishment = punishment; } public void copyWord() { int count = 0; String threadName = Thread.currentThread().getName(); while (true) { if (punishment.getLeftCopyCount() > 0) { int leftCopyCount = punishment.getLeftCopyCount(); System.out.println(threadName+"線程-"+name + "抄寫" + punishment.getWordToCopy() + "。還要抄寫" + --leftCopyCount + "次"); punishment.setLeftCopyCount(leftCopyCount); count++; } else { break; } } System.out.println(threadName+"線程-"+name + "一共抄寫了" + count + "次!"); } } ~~~ Student 構造函數傳入 Punishment。copyWord 方法是根據懲罰內容。完成單詞抄寫的主要邏輯。 我們重點看一下 coppyWord 方法。count 變量是計數器,記錄抄寫的總次數。threadName 是本線程的名稱,這里通過 Thread 的靜態方法 currentThread 取得當前線程,然后通過 getName 方法獲取線程名稱。 在 while 循環體中,當 punishment 的剩余抄寫次數大于 0 時,執行抄寫邏輯,否則抄寫任務完成,跳出循環。邏輯很簡單,相信大家都能看懂。接下來我們通過 main 方法嘗試運行,看看效果。main 方法代碼如下: ~~~java public class StudentClient { public static void main(String[] args) { Punishment punishment = new Punishment(100,"internationalization"); Student student = new Student("小明",punishment); student.copyWord(); } } ~~~ 輸出如下: ~~~ main線程-小明抄寫internationalization。還要抄寫99次 .........(中間省略) main線程-小明抄寫internationalization。還要抄寫0次 main線程-小明一共抄寫了100次! ~~~ 在控制臺可以清楚地看到小明抄寫了 100 次單詞。不過此時的代碼并沒有引入多線程,是單線程小明在工作。唯一看到的和線程沾邊的就是日志中的 “main 線程”,這是通過 Thread.*currentThread*().getName () 獲取的當前線程名稱,也就是 main 函數所在的線程。 ## 3\. 繼承 Thread 實現獨立線程單詞抄寫 接下來我們嘗試為小明單獨起一個線程做這個事情,而不是在 main 線程中完成。回到我們所講的主題,實現多線程的方式上,我們先采用繼承 thread 類,重寫 run 方法的方式。改版后,student 代碼如下: ~~~java //1、繼承Thread類 public class Student extends Thread{ private String name; private Punishment punishment; public Student(String name, Punishment punishment) { //2、調用Thread構造方法,設置threadName super(name); this.name=name; this.punishment = punishment; } public void copyWord() { int count = 0; String threadName = Thread.currentThread().getName(); while (true) { if (punishment.getLeftCopyCount() > 0) { int leftCopyCount = punishment.getLeftCopyCount(); System.out.println(threadName+"線程-"+name + "抄寫" + punishment.getWordToCopy() + "。還要抄寫" + --leftCopyCount + "次"); punishment.setLeftCopyCount(leftCopyCount); count++; } else { break; } } System.out.println(threadName+"線程-"+name + "一共抄寫了" + count + "次!"); } //3、重寫run方法,調用copyWord完成任務 @Override public void run(){ copyWord(); } } ~~~ 三個變化點在代碼中已經標出。不再多說,只提醒下,在第 2 個點,我們設置了線程的名稱,一會在輸出中會看到帶來的變化。 main 方法代碼如下: ~~~java public class StudentClient { public static void main(String[] args) { Punishment punishment = new Punishment(100,"internationalization"); Student student = new Student("小明",punishment); student.start(); } } ~~~ 可以看到此時調用的不是 student 的 copyWord 方法,而是調用了 start 方法。start 方法是從 Thread 類繼承而來,調用后線程進入就緒狀態,等待 CPU 的調用。而 start 方法最終會觸發執行 run 方法,在 run 方法中 copyWord 被執行。輸出如下: ~~~ 小明線程-小明抄寫internationalization。還要抄寫99次 ......(中間省略) 小明線程-小明抄寫internationalization。還要抄寫0次 小明線程-小明一共抄寫了100次! ~~~ 我們可以看到,現在不再是 main 線程在工作了,而是小明線程。這說明 student 已經工作在 “小明” 線程上。為了更加直觀,我們在 student.start () 后面加一行代碼: ~~~java System.out.println("Another thread will finish the punishment。 main thread is finished" ); ~~~ 再次運行程序,輸出如下: ~~~ Another thread to finish the punishment。main thread is finished 小明線程-小明抄寫internationalization。還要抄寫99次 ......(中間省略) 小明線程-小明抄寫internationalization。還要抄寫0次 小明線程-小明一共抄寫了100次! ~~~ 可以看到主線程在 student.start () 后,會立即向下執行。而小明線程則在獨立執行 copyWord 方法。這里你可以做個對比,單線程情況下,一定是在小明抄寫的所有輸出后才會輸出 “main thread is finished”。 ## 4\. 多線程并發實現單詞抄寫 你心里一定在想,這個例子沒有看到多線程的好處啊?是的,如果僅僅是小明一個人去完成任務,其實和單線程沒有區別。但是假如小明找來了幾個同學幫他一起寫呢? 我們在 main 方法中啟動多個線程一塊完成單詞抄寫任務: ~~~java public static void main(String[] args) { Punishment punishment = new Punishment(100,"internationalization"); Student xiaoming = new Student("小明",punishment); xiaoming.start(); Student xiaozhang = new Student("小張",punishment); xiaozhang.start(); Student xiao趙 = new Student("小趙",punishment); xiaozhang.start(); } ~~~ 大家對這段代碼的期望結果是什么呢?按照正常的邏輯,應該是小明先開始寫,他會抄寫的次數多一點,而小張和小趙抄寫的次數少一點,但是三人抄寫的總量應該是 100。不過事與愿違,我們在控制臺可以看到如下輸出: ~~~ 小趙線程-小趙一共抄寫了100次! 小明線程-小明一共抄寫了100次! 小張線程-小張一共抄寫了100次! ~~~ 小明的工作量不但沒有減少,還連累小張和小趙白白抄寫了 100 遍,為什么會這樣呢?!我在下篇專欄中會詳細解答。這里我可以先肯定的告訴你,我們是有辦法解決現在的問題,達到想要的執行效果。本篇文章我們還是聚焦在多線程如何實現上。 接下來,我們看另外一種多線程實現方式。 ## 5\. 實現 Runnable 接口,啟用單獨線程抄寫單詞 上面講解了通過繼承 Thread 的方式來實現多線程,接下來我們看看如何以實現 Runnable 接口的形式實現多線程。student 代碼改造后如下: ~~~java public class Student implements Runnable{ private String name; private Punishment punishment; public Student(String name, Punishment punishment) { this.name=name; this.punishment = punishment; } public void copyWord() { int count = 0; String threadName = Thread.currentThread().getName(); while (true) { if (punishment.getLeftCopyCount() > 0) { int leftCopyCount = punishment.getLeftCopyCount(); System.out.println(threadName+"線程-"+name + "抄寫" + punishment.getWordToCopy() + "。還要抄寫" + --leftCopyCount + "次"); punishment.setLeftCopyCount(leftCopyCount); count++; } else { break; } } System.out.println(threadName+"線程-"+name + "一共抄寫了" + count + "次!"); } //重寫run方法,完成任務。 @Override public void run(){ copyWord(); } } ~~~ 和繼承 thread 實現多線程的區別,在于現在是實現 runnable 接口。不過也是需要實現 run () 方法。另外由于 runnable 是接口,所以之前構造函數中調用父類構造函數的語句需要去掉。 我們再看看 StudentClient 的代碼: ~~~java public class StudentClient { public static void main(String[] args) { Punishment punishment = new Punishment(100,"internationalization"); Thread xiaoming = new Thread(new Student("小明",punishment),"小明"); xiaoming.start(); } } ~~~ 可以看到我們需要創建一個 thread,把實現了 runnable 接口的對象通過構造函數傳遞進去,Thread 構造函數的第二個參數是自定義的 thread name。之前由于 Student 就是 Thread 的子類,所以我們直接通過 new Student 就可以得到線程對象。最后都是通過調用 Thread 對象的 start 方法來啟動線程。運行代碼后發現輸出結果和繼承 thread 方式是一模一樣的。 ## 6\. 總結 本篇講解的內容非常基礎,目的在于讓大家對多線程開發有所感知,快速上手。建議大家自己把代碼敲一邊,體會兩種啟動線程方式的異同。此外,可以重點思考下,為什么多線程并發時,結果并不是我們所期望的。看一看你的答案是否和下篇專欄所寫的原因一樣。通過本篇學習,我們知道在 java 中啟動多線程非常簡單。但是,要想處理好多線程間的協調,并不是一個容易的事情。而多線程開發的難點也就在于此。下一節我們就來看看多線程開發中會遇到的問題。
                  <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>

                              哎呀哎呀视频在线观看