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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 簡介 線程:線程是進程中的一個執行單元,負責當前進程中程序的執行,一個進程中至少有一個線程。一個進程中是可以有多個線程的,這個應用程序也可以稱之為多線程程序。 簡而言之:一個程序運行后至少有一個進程,一個進程中可以包含多個線程 * 程序運行原理 - 分時調度 所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間。 - 搶占式調度 優先讓優先級高的線程使用 CPU,如果線程的優先級相同,那么會隨機選擇一個(線程隨機性),Java使用的為搶占式調度。 其實,多線程程序并不能提高程序的運行速度,但能夠提高程序運行效率,讓CPU的使用率更高。 # Thread類 Thread是程序中的執行線程。Java 虛擬機允許應用程序并發地運行多個執行線程。 ![](https://box.kancloud.cn/85bb844331142419228e8e089ead3c03_395x382.png) * 構造方法 ~~~ Thread() 分配新的Thread對象 Thread(String name) 分配新的Thread對象.將指定的name作為其線程名稱 ~~~ * 常用方法 ~~~ void start() 使該線程開始執行,java虛擬機調用該線程的run方法 void run() 該線程要執行的操作 static void sleep(long millis) 在定義的毫秒數內讓當前正在執行的線程休眠(暫停執行) ~~~ 創建新執行線程有兩種方法。 * 一種方法是將類聲明為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。創建對象,開啟線程。run方法相當于其他線程的main方法。 * 另一種方法是聲明一個實現 Runnable 接口的類。該類然后實現 run 方法。然后創建Runnable的子類對象,傳入到某個線程的構造方法中,開啟線程。 # 創建線程一 ## 繼承Thread類 創建線程的步驟: 1. 定義一個類繼承Thread。 2. 重寫run方法。 3. 創建子類對象,就是創建線程對象。 4. 調用start方法,開啟線程并讓線程執行,同時還會告訴jvm去調用run方法。 * 測試類 ~~~ public class Demo01 { public static void main(String[] args) { //創建自定義線程對象 MyThread mt = new MyThread("新的線程!"); //開啟新線程 mt.start(); //在主方法中執行for循環 for (int i = 0; i < 10; i++) { System.out.println("main線程!"+i); } } } ~~~ * 自定義線程類 ~~~ public class MyThread extends Thread { //定義指定線程名稱的構造方法 public MyThread(String name) { //調用父類的String參數的構造方法,指定線程的名稱 super(name); } /* * 重寫run方法,完成該線程執行的邏輯 */ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+":正在執行!"+i); } } } ~~~ 思考:線程對象調用 run方法和調用start方法區別? 線程對象調用run方法不開啟線程。僅是對象調用方法。線程對象調用start開啟線程,并讓jvm調用run方法在開啟的線程中執行。 ### 原理 * 繼承Thread類原理 我們為什么要繼承Thread類,并調用其的start方法才能開啟線程呢? 繼承Thread類:因為Thread類用來描述線程,具備線程應該有功能。那為什么不直接創建Thread類的對象呢?如下代碼: ~~~ Thread t1 = new Thread(); ~~~ t1.start();//這樣做沒有錯,但是該start調用的是Thread類中的run方法,而這個run方法沒有做什么事情,更重要的是這個run方法中并沒有定義我們需要讓線程執行的代碼。 創建線程的目的是什么? 是為了建立程序單獨的執行路徑,讓多部分代碼實現同時執行。也就是說線程創建并執行需要給定線程要執行的任務。 對于之前所講的主線程,它的任務定義在main函數中。自定義線程需要執行的任務都定義在run方法中。 Thread類run方法中的任務并不是我們所需要的,只有重寫這個run方法。既然Thread類已經定義了線程任務的編寫位置(run方法),那么只要在編寫位置(run方法)中定義任務代碼即可。所以進行了重寫run方法動作。 ### 獲取線程名稱 開啟的線程都會有自己的獨立運行棧內存,那么這些運行的線程的名字是什么呢?該如何獲取呢?既然是線程的名字,按照面向對象的特點,是哪個對象的屬性和誰的功能,那么我們就去找那個對象就可以了。查閱Thread類的API文檔發現有個方法是獲取當前正在運行的線程對象。還有個方法是獲取當前線程對象的名稱。既然找到了,我們就可以試試。 ~~~ static Thread currentThread() 返回對當前正在執行的線程對象的引用 String getName() 返回該線程的名稱 ~~~ * Thread.currentThread()獲取當前線程對象 * Thread.currentThread().getName();獲取當前線程對象的名稱 ~~~ class MyThread extends Thread { //繼承Thread MyThread(String name){ super(name); } //復寫其中的run方法 public void run(){ for (int i=1;i<=20 ;i++ ){ System.out.println(Thread.currentThread().getName()+",i="+i); } } } class ThreadDemo { public static void main(String[] args) { //創建兩個線程任務 MyThread d = new MyThread(); MyThread d2 = new MyThread(); d.run();//沒有開啟新線程, 在主線程調用run方法 d2.start();//開啟一個新線程,新線程調用run方法 } } ~~~ 通過結果觀察,原來主線程的名稱:main;自定義的線程:Thread-0,線程多個時,數字順延。如Thread-1...... 進行多線程編程時,不要忘記了Java程序運行是從主線程開始,main方法就是主線程的線程執行內容。 # 創建線程二 ## 實現Runnable接口 創建線程的另一種方法是聲明實現 Runnable 接口的類。該類然后實現 run 方法。然后創建Runnable的子類對象,傳入到某個線程的構造方法中,開啟線程。 ![](https://box.kancloud.cn/d6069dc60035ae084950bb5126166a5d_391x182.png) **接口中的方法** ~~~ void run() 使用實現接口Runnable的對象創建一個線程時,啟動該線程將導致在獨立執行的線程中調用對象的run方法 ~~~ **Thread類構造方法** ~~~ Thread(Runnable target) 分配新的Thread對象,以便將target作為其運行對象 Thread(Runnable target, String name) 分配新的對象,以便將targe作為其運行對象,將指定name作為其名稱 ~~~ ## 步驟 創建線程的步驟。 1. 定義類實現Runnable接口。 2. 覆蓋接口中的run方法。。 3. 創建Thread類的對象 4. 將Runnable接口的子類對象作為參數傳遞給Thread類的構造函數。 5. 調用Thread類的start方法開啟線程 * 代碼演示: ~~~ public class Demo02 { public static void main(String[] args) { //創建線程執行目標類對象 Runnable runn = new MyRunnable(); //將Runnable接口的子類對象作為參數傳遞給Thread類的構造函數 Thread thread = new Thread(runn); Thread thread2 = new Thread(runn); //開啟線程 thread.start(); thread2.start(); for (int i = 0; i < 10; i++) { System.out.println("main線程:正在執行!"+i); } } } ~~~ * 自定義線程執行任務類 ~~~ public class MyRunnable implements Runnable{ //定義線程要執行的run方法邏輯 @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("我的線程:正在執行!"+i); } } } ~~~ ## 原理 實現Runnable接口,避免了繼承Thread類的單繼承局限性。覆蓋Runnable接口中的run方法,將線程任務代碼定義到run方法中。 創建Thread類的對象,只有創建Thread類的對象才可以創建線程。線程任務已被封裝到Runnable接口的run方法中,而這個run方法所屬于Runnable接口的子類對象,所以將這個子類對象作為參數傳遞給Thread的構造函數,這樣,線程對象創建時就可以明確要運行的線程的任務。 ## 好處 實現Runnable接口避免了單繼承的局限性,所以較為常用。 實現Runnable接口的方式,更加的符合面向對象,線程分為兩部分,一部分線程對象,一部分線程任務。繼承Thread類,線程對象和線程任務耦合在一起。一旦創建Thread類的子類對象,既是線程對象,有又有線程任務。實現runnable接口,將線程任務單獨分離出來封裝成對象,類型就是Runnable接口類型。Runnable接口對線程對象和線程任務進行解耦。 # 創建線程三 ## 實現Callable接口 使用Runnable接口實現的多線程可以避免單繼承局限,但是他不能返回結果. 為了解決這個,提供了一個新的接口java.util.concurrent.Callable ~~~ @FunctionalInterface public interface Callable<V> { V call() throws Exception; } ~~~ call()方法執行完線程的主題功能之后可以返回一個結果,而返回結果的類型由Callable的泛型決定 ## 步驟 實現Callable接口 Thread類里面沒有發現并沒有直接支持Callable接口的多線程應用 從jdk1.5開始提供有`java.util.concurrent.FutureTask<V>`類,這個類主要負責Callable ~~~ public class FutureTask<V> extends Object implement RunnableFuture<V> ~~~ 發現他實現了RunnableFuture ~~~ public interface RunnableFuture<V> extends Runnable, Future<V> ~~~ 然后我們看,在FutureTask類里面定義有如下結構的構造方法: ~~~ public FutureTask(Callable<V> callable) ~~~ 接收的目的只有一個,那么取得call()方法的返回結果 FutureTask是Runnable接口的子類,所以可以使用Thread類的構造來接收task對象 多線程執行完畢可以取得內容,依靠FutureTask的父接口Future中的get()方法完成 ## 例子 ~~~ package com.study; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class MyThread implements Callable<String> { private int ticket = 10; @Override public String call() throws Exception { for (int i = 0; i < 100; i++) { if (this.ticket > 0) { System.out.println("賣票--- " + this.ticket--); } } return "賣光了"; } } public class HelloWorld { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); //目的為了取得線程的返回值,String是泛型,對應返回類型 FutureTask<String> task1 = new FutureTask<>(m1); FutureTask<String> task2 = new FutureTask<>(m2); //FutureTask是Runnable接口的子類,所以可以使用Thread類的構造來接收task對象 //啟動多線程 new Thread(task1).start(); new Thread(task2).start(); //多線程執行完畢可以取得內容,依靠FutureTask的父接口Future中的get()方法完成 System.out.println("A線程返回結果: "+ task1.get()); System.out.println("B線程返回結果: "+ task2.get()); } } ~~~ # 線程的匿名內部類使用 使用線程的內匿名內部類方式,可以方便的實現每個線程執行不同的線程任務操作。 * 方式1:創建線程對象時,直接重寫Thread類中的run方法 ~~~ new Thread() { public void run() { for (int x = 0; x < 40; x++) { System.out.println(Thread.currentThread().getName() + "...X...." + x); } } }.start(); ~~~ * 方式2:使用匿名內部類的方式實現Runnable接口,重新Runnable接口中的run方法 ~~~ Runnable r = new Runnable() { public void run() { for (int x = 0; x < 40; x++) { System.out.println(Thread.currentThread().getName() + "...Y...." + x); } } }; new Thread(r).start(); ~~~ # 查看源碼 首先方法在Thread類的start()方法里面存放有一個IllegalThreadStateException,按道理應該使用try...catch處理.或者在start()方法聲明上這樣的異常代碼,因為此異常屬于RuntimeException的子類.屬于選擇性處理.如果對一個線程對象重復啟動,那么就會拋異常 發現在start()方法里面要調用一個start0()方法,而且此方法的結構和抽象方法類似. 開發里面有一門技術叫做JNI技術(java Native Interface)這門技術的特點:是使用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>

                              哎呀哎呀视频在线观看