django vue 實戰
一·基本概念
1.1程式和程序的概念
-
程式 - 資料結構 + 演算法,主要指存放在硬碟上的可執行檔案。
-
程序 - 主要指執行在記憶體中的可執行檔案。
-
目前主流的作業系統都支援多程序,為了讓作業系統同時可以執行多個任務,但程序是重量級的,
-
也就是新建一個程序會消耗CPU和記憶體空間等系統資源,因此程序的數量比較侷限。
1.2 執行緒的概念
-
為了解決上述問題就提出執行緒的概念,執行緒就是程序內部的程式流,也就是說作業系統內部支援多 程序的,而每個程序的內部又是支援多執行緒的,執行緒是輕量的,新建執行緒會共享所在程序的系統資 源,因此目前主流的開發都是採用多執行緒。
-
多執行緒是採用時間片輪轉法來保證多個執行緒的併發執行,所謂併發就是指巨集觀並行微觀序列的機 制。
二· 執行緒的建立
2.1Thread類的概念
-
java.lang.Thread類代表執行緒,任何執行緒物件都是Thread類(子類)的例項。
-
Thread類是執行緒的模板,封裝了複雜的執行緒開啟等操作,封裝了作業系統的差異性。
2.2 建立方式
-
自定義類繼承Thread類並重寫run方法,然後建立該類的物件呼叫start方法。
-
自定義類實現Runnable介面並重寫run方法,建立該類的物件作為實參來構造Thread型別的對 象,然後使用Thread型別的物件呼叫start方法。
2.3相關方法
方法宣告 | 功能介紹 |
---|---|
Thread() | 使用無參的方式構造物件 |
Thread(String name) | 根據引數指定的名稱來構造物件 |
Thread(Runnable target) | 根據引數指定的引用來構造物件,其中Runnable是個介面類 型 |
Thread(Runnable target, String name) | 根據引數指定引用和名稱來構造物件 |
void run() | 若使用Runnable引用構造了執行緒物件,呼叫該方法時最終調 用介面中的版本 若沒有使用Runnable引用構造執行緒物件,呼叫該方法時則啥 也不做 |
void start() | 用於啟動執行緒,Java虛擬機器會自動呼叫該執行緒的run方法 |
2.4 執行流程
-
執行main方法的執行緒叫做主執行緒,執行run方法的執行緒叫做新執行緒/子執行緒。
-
main方法是程式的入口,對於start方法之前的程式碼來說,由主執行緒執行一次,當start方法呼叫成 功後執行緒的個數由1個變成了2個,新啟動的執行緒去執行run方法的程式碼,主執行緒繼續向下執行,兩 個執行緒各自獨立執行互不影響。
-
當run方法執行完畢後子執行緒結束,當main方法執行完畢後主執行緒結束。
-
兩個執行緒執行沒有明確的先後執行次序,由作業系統排程演算法來決定。
2.5 方式的比較
-
繼承Thread類的方式程式碼簡單,但是若該類繼承Thread類後則無法繼承其它類,而實現 Runnable介面的方式程式碼複雜,但不影響該類繼承其它類以及實現其它介面,因此以後的開發中 推薦使用第二種方式。
public class SubRunnableRun implements Runnable { @Override public void run() { // 列印1 ~ 20之間的所有整數 for (int i = 1; i <= 20; i++) { System.out.println("run方法中:i = " + i); // 1 2 ... 20 } } } public class SubRunnableTest { public static void main(String[] args) { SubRunnable1 sr1 = new SubRunnable1(); SubRunnable2 sr2 = new SubRunnable2(); Thread t1 = new Thread(sr1); Thread t2 = new Thread(sr2); t1.start(); t2.start(); System.out.println("主執行緒開始等待..."); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主執行緒等待結束!"); } } //繼承Thread類實現多執行緒 public class SubThreadRun extends Thread { @Override public void run() { // 列印1 ~ 20之間的所有整數 for (int i = 1; i <= 20; i++) { System.out.println("run方法中:i = " + i); // 1 2 ... 20 } } } public class SubThreadRunTest { public static void main(String[] args) { // 1.宣告Thread型別的引用指向子類型別的物件 Thread t1 = new SubThreadRun(); // 2.呼叫run方法測試,本質上就是相當於對普通成員方法的呼叫,因此執行流程就是run方法的程式碼執行完畢後才能繼續向下執行 //t1.run(); // 用於啟動執行緒,Java虛擬機器會自動呼叫該執行緒類中的run方法 // 相當於又啟動了一個執行緒,加上執行main方法的執行緒是兩個執行緒 t1.start(); // 列印1 ~ 20之間的所有整數 for (int i = 1; i <= 20; i++) { System.out.println("-----------------main方法中:i = " + i); // 1 2 ... 20 } } }
public class ThreadNoNameTest { public static void main(String[] args) { // 匿名內部類的語法格式:父類/介面型別 引用變數名 = new 父類/介面型別() { 方法的重寫 }; // 1.使用繼承加匿名內部類的方式建立並啟動執行緒 /*Thread t1 = new Thread() { @Override public void run() { System.out.println("張三說:在嗎?"); } }; t1.start();*/ new Thread() { @Override public void run() { System.out.println("張三說:在嗎?"); } }.start(); // 2.使用實現介面加匿名內部類的方式建立並啟動執行緒 /*Runnable ra = new Runnable() { @Override public void run() { System.out.println("李四說:不在。"); } }; Thread t2 = new Thread(ra); t2.start();*/ /*new Thread(new Runnable() { @Override public void run() { System.out.println("李四說:不在。"); } }).start();*/ // Java8開始支援lambda表示式: (形參列表)->{方法體;} /*Runnable ra = ()-> System.out.println("李四說:不在。"); new Thread(ra).start();*/ new Thread(()-> System.out.println("李四說:不在。")).start(); } }
三·執行緒的生命週期
-
新建狀態 - 使用new關鍵字建立之後進入的狀態,此時執行緒並沒有開始執行。
-
就緒狀態 - 呼叫start方法後進入的狀態,此時執行緒還是沒有開始執行。
-
執行狀態 - 使用執行緒排程器呼叫該執行緒後進入的狀態,此時執行緒開始執行,當執行緒的時間片執行完 畢後任務沒有完成時回到就緒狀態。
-
消亡狀態 - 當執行緒的任務執行完成後進入的狀態,此時執行緒已經終止。
-
阻塞狀態 - 當執行緒執行的過程中發生了阻塞事件進入的狀態,如:sleep方法。 阻塞狀態解除後進入就緒狀態。
四·執行緒的編號和名稱
方法宣告 | 功能介紹 |
---|---|
long getId() | 獲取呼叫物件所表示執行緒的編號 |
String getName() | 獲取呼叫物件所表示執行緒的名稱 |
void setName(String name) | 設定/修改執行緒的名稱為引數指定的數值 |
static Thread currentThread() | 獲取當前正在執行執行緒的引用 |
public class ThreadIdNameTest extends Thread { public ThreadIdNameTest(String name) { super(name); // 表示呼叫父類的構造方法 } @Override public void run() { System.out.println("子執行緒的編號是:" + getId() + ",名稱是:" + getName()); // 14 Thread-0 guanyu // 修改名稱為"zhangfei" setName("zhangfei"); System.out.println("修改後子執行緒的編號是:" + getId() + ",名稱是:" + getName()); // 14 zhangfei } public static void main(String[] args) { ThreadIdNameTest tint = new ThreadIdNameTest("guanyu"); tint.start(); // 獲取當前正在執行執行緒的引用,當前正在執行的執行緒是主執行緒,也就是獲取主執行緒的引用 Thread t1 = Thread.currentThread(); System.out.println("主執行緒的編號是:" + t1.getId() + ", 名稱是:" + t1.getName()); } }
方法宣告 | 功能介紹 |
---|---|
static void yield() | 當前執行緒讓出處理器(離開Running狀態),使當前執行緒進入Runnable 狀態等待 |
static void sleep(times) | 使當前執行緒從 Running 放棄處理器進入Block狀態, 休眠times毫秒, 再返 回到Runnable如果其他執行緒打斷當前執行緒的Block(sleep), 就會發生 InterruptedException。 |
int getPriority() | 獲取執行緒的優先順序 |
void setPriority(int newPriority) | 修改執行緒的優先順序。 優先順序越高的執行緒不一定先執行,但該執行緒獲取到時間片的機會會更多 一些 |
void join() | 等待該執行緒終止 |
void join(long millis) | 等待引數指定的毫秒數 |
boolean isDaemon() | 用於判斷是否為守護執行緒 |
void setDaemon(boolean on) |
//關於優先順序 public class ThreadPriorityTest extends Thread { @Override public void run() { //System.out.println("子執行緒的優先順序是:" + getPriority()); // 5 10 優先順序越高的執行緒不一定先執行。 for (int i = 0; i < 20; i++) { System.out.println("子執行緒中:i = " + i); } } public static void main(String[] args) { ThreadPriorityTest tpt = new ThreadPriorityTest(); // 設定子執行緒的優先順序 tpt.setPriority(Thread.MAX_PRIORITY); tpt.start(); Thread t1 = Thread.currentThread(); //System.out.println("主執行緒的優先順序是:" + t1.getPriority()); // 5 普通的優先順序 for (int i = 0; i < 20; i++) { System.out.println("--主執行緒中:i = " + i); } } } //關於sleep public class ThreadSleepTest extends Thread { // 宣告一個布林型別的變數作為迴圈是否執行的條件 private boolean flag = true; // 子類中重寫的方法不能丟擲更大的異常 @Override public void run() { // 每隔一秒獲取一次系統時間並列印,模擬時鐘的效果 while (flag) { // 獲取當前系統時間並調整格式列印 // LocalDateTime.now(); Date d1 = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(d1)); // 睡眠1秒鐘 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { ThreadSleepTest tst = new ThreadSleepTest(); tst.start(); // 主執行緒等待5秒後結束子執行緒 System.out.println("主執行緒開始等待..."); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // 停止子執行緒 過時 不建議使用 //tst.stop(); tst.flag = false; System.out.println("主執行緒等待結束!"); } } //關於join public class ThreadJoinTest extends Thread { @Override public void run() { // 模擬倒數10個數的效果 System.out.println("倒計時開始..."); for (int i = 10; i > 0; i--) { System.out.println(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("新年快樂!"); } public static void main(String[] args) { ThreadJoinTest tjt = new ThreadJoinTest(); tjt.start(); // 主執行緒開始等待 System.out.println("主執行緒開始等待..."); try { // 表示當前正在執行的執行緒物件等待呼叫執行緒物件,也就是主執行緒等待子執行緒終止 //tjt.join(); tjt.join(5000); // 最多等待5秒 } catch (InterruptedException e) { e.printStackTrace(); } //System.out.println("終於等到你,還好沒放棄!"); System.out.println("可惜不是你,陪我到最後!"); } } //關於守護執行緒 public class ThreadDaemonTest extends Thread { @Override public void run() { //System.out.println(isDaemon()? "該執行緒是守護執行緒": "該執行緒不是守護執行緒"); // 預設不是守護執行緒 // 當子執行緒不是守護執行緒時,雖然主執行緒先結束了,但是子執行緒依然會繼續執行,直到列印完畢所有資料為止 // 當子執行緒是守護執行緒時,當主執行緒結束後,則子執行緒隨之結束 for (int i = 0; i < 50; i++) { System.out.println("子執行緒中:i = " + i); } } public static void main(String[] args) { ThreadDaemonTest tdt = new ThreadDaemonTest(); // 必須線上程啟動之前設定子執行緒為守護執行緒 tdt.setDaemon(true); tdt.start(); for (int i = 0; i < 20; i++) { System.out.println("-------主執行緒中:i = " + i); } } }
六·執行緒同步機制
6.1基本概念
-
當多個執行緒同時訪問同一種共享資源時,可能會造成資料的覆蓋等不一致性問題,此時就需要對線 程之間進行通訊和協調,該機制就叫做執行緒的同步機制。
-
多個執行緒併發讀寫同一個臨界資源時會發生執行緒併發安全問題。
-
非同步操作:多執行緒併發的操作,各自獨立執行。
-
同步操作:多執行緒序列的操作,先後執行的順序。
6.2 解決方案
-
由程式結果可知:當兩個執行緒同時對同一個賬戶進行取款時,導致最終的賬戶餘額不合理。
-
引發原因:執行緒一執行取款時還沒來得及將取款後的餘額寫入後臺,執行緒二就已經開始取款。
-
解決方案:讓執行緒一執行完畢取款操作後,再讓執行緒二執行即可,將執行緒的併發操作改為序列操 作。
-
經驗分享:在以後的開發儘量減少序列操作的範圍,從而提高效率
6.3 實現方式
在Java語言中使用synchronized關鍵字來實現同步/物件鎖機制從而保證執行緒執行的原子性,具體 方式如下: 使用同步程式碼塊的方式實現部分程式碼的鎖定,格式如下: synchronized(類型別的引用) { 編寫所有需要鎖定的程式碼; } 使用同步方法的方式實現所有程式碼的鎖定。 直接使用synchronized關鍵字來修飾整個方法即可 該方式等價於: synchronized(this) { 整個方法體的程式碼 }
靜態方法的鎖定
當我們對一個靜態方法加鎖,如: public synchronized static void xxx(){….} 那麼該方法鎖的物件是類物件。每個類都有唯一的一個類物件。獲取類物件的方式:類名.class。 靜態方法與非靜態方法同時使用了synchronized後它們之間是非互斥關係的。 原因在於:靜態方法鎖的是類物件而非靜態方法鎖的是當前方法所屬物件。
6.5 注意事項
-
使用synchronized保證執行緒同步應當注意: 多個需要同步的執行緒在訪問同步塊時,看到的應該是同一個鎖物件引用。
-
在使用同步塊時應當儘量減少同步範圍以提高併發的執行效率。
6.6執行緒安全類和不安全類
-
StringBuffer類是執行緒安全的類,但StringBuilder類不是執行緒安全的類。
-
Vector類和 Hashtable類是執行緒安全的類,但ArrayList類和HashMap類不是執行緒安全的類。
-
Collections.synchronizedList() 和 Collections.synchronizedMap()等方法實現安全。
6.7 死鎖的概念
執行緒一執行的程式碼: public void run(){ synchronized(a){ //持有物件鎖a,等待物件鎖b synchronized(b){ 編寫鎖定的程式碼; } } } 執行緒二執行的程式碼: public void run(){ synchronized(b){ //持有物件鎖b,等待物件鎖a synchronized(a){ 編寫鎖定的程式碼; } } } 注意: 在以後的開發中儘量減少同步的資源,減少同步程式碼塊的巢狀結構的使用!
6.8 使用Lock(鎖)實現執行緒同步
-
從Java5開始提供了更強大的執行緒同步機制—使用顯式定義的同步鎖物件來實現。
-
java.util.concurrent.locks.Lock介面是控制多個執行緒對共享資源進行訪問的工具。
-
該介面的主要實現類是ReentrantLock類,該類擁有與synchronized相同的併發性,在以後的執行緒 安全控制中,經常使用ReentrantLock類顯式加鎖和釋放鎖。
public class AccountRunnableTest implements Runnable { private int balance; // 用於描述賬戶的餘額 private Demo dm = new Demo(); private ReentrantLock lock = new ReentrantLock(); // 準備了一把鎖 public AccountRunnableTest() { } public AccountRunnableTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public /*synchronized*/ void run() { // 開始加鎖 lock.lock(); // 由原始碼可知:最終是account物件來呼叫run方法,因此當前正在呼叫的物件就是account,也就是說this就是account //synchronized (this) { // ok System.out.println("執行緒" + Thread.currentThread().getName() + "已啟動..."); //synchronized (dm) { // ok //synchronized (new Demo()) { // 鎖不住 要求必須是同一個物件 // 1.模擬從後臺查詢賬戶餘額的過程 int temp = getBalance(); // temp = 1000 temp = 1000 // 2.模擬取款200元的過程 if (temp >= 200) { System.out.println("正在出鈔,請稍後..."); temp -= 200; // temp = 800 temp = 800 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("請取走您的鈔票!"); } else { System.out.println("餘額不足,請核對您的賬戶餘額!"); } // 3.模擬將最新的賬戶餘額寫入到後臺 setBalance(temp); // balance = 800 balance = 800 //} lock.unlock(); // 實現解鎖 } public static void main(String[] args) { AccountRunnableTest account = new AccountRunnableTest(1000); //AccountRunnableTest account2 = new AccountRunnableTest(1000); Thread t1 = new Thread(account); Thread t2 = new Thread(account); //Thread t2 = new Thread(account2); t1.start(); t2.start(); System.out.println("主執行緒開始等待..."); try { t1.join(); //t2.start(); // 也就是等待執行緒一取款操作結束後再啟動執行緒二 t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最終的賬戶餘額為:" + account.getBalance()); // 600 800 } } class Demo{}
public class AccountThreadTest extends Thread { private int balance; // 用於描述賬戶的餘額 private static Demo dm = new Demo(); // 隸屬於類層級,所有物件共享同一個 public AccountThreadTest() { } public AccountThreadTest(int balance) { this.balance = balance; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public /*static*/ /*synchronized*/ void run() { /*System.out.println("執行緒" + Thread.currentThread().getName() + "已啟動..."); //synchronized (dm) { // ok //synchronized (new Demo()) { // 鎖不住 要求必須是同一個物件 // 1.模擬從後臺查詢賬戶餘額的過程 int temp = getBalance(); // temp = 1000 temp = 1000 // 2.模擬取款200元的過程 if (temp >= 200) { System.out.println("正在出鈔,請稍後..."); temp -= 200; // temp = 800 temp = 800 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("請取走您的鈔票!"); } else { System.out.println("餘額不足,請核對您的賬戶餘額!"); } // 3.模擬將最新的賬戶餘額寫入到後臺 setBalance(temp); // balance = 800 balance = 800 //}*/ test(); } public /*synchronized*/ static void test() { synchronized (AccountThreadTest.class) { // 該型別對應的Class物件,由於型別是固定的,因此Class物件也是唯一的,因此可以實現同步 System.out.println("執行緒" + Thread.currentThread().getName() + "已啟動..."); //synchronized (dm) { // ok //synchronized (new Demo()) { // 鎖不住 要求必須是同一個物件 // 1.模擬從後臺查詢賬戶餘額的過程 int temp = 1000; //getBalance(); // temp = 1000 temp = 1000 // 2.模擬取款200元的過程 if (temp >= 200) { System.out.println("正在出鈔,請稍後..."); temp -= 200; // temp = 800 temp = 800 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("請取走您的鈔票!"); } else { System.out.println("餘額不足,請核對您的賬戶餘額!"); } // 3.模擬將最新的賬戶餘額寫入到後臺 //setBalance(temp); // balance = 800 balance = 800 } } public static void main(String[] args) { AccountThreadTest att1 = new AccountThreadTest(1000); att1.start(); AccountThreadTest att2 = new AccountThreadTest(1000); att2.start(); System.out.println("主執行緒開始等待..."); try { att1.join(); //t2.start(); // 也就是等待執行緒一取款操作結束後再啟動執行緒二 att2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最終的賬戶餘額為:" + att1.getBalance()); // 800 } }
與synchronized方式的比較
-
Lock是顯式鎖,需要手動實現開啟和關閉操作,而synchronized是隱式鎖,執行鎖定程式碼後自動
-
Lock只有同步程式碼塊方式的鎖,而synchronized有同步程式碼塊方式和同步方法兩種鎖。 使用Lock鎖方式時,Java虛擬機器將花費較少的時間來排程執行緒,因此效能更好。
七·Object類常用的方法
方法宣告 | 功能介紹 |
---|---|
void wait() | 用於使得執行緒進入等待狀態,直到其它執行緒呼叫notify()或notifyAll()方 法 |
void wait(long timeout) | 用於進入等待狀態,直到其它執行緒呼叫方法或引數指定的毫秒數已經過 去為止 |
void notify() | 用於喚醒等待的單個執行緒 |
void notifyAll() | 用於喚醒等待的所有執行緒 |
public class ThreadCommunicateTest implements Runnable { private int cnt = 1; @Override public void run() { while (true) { synchronized (this) { // 每當有一個執行緒進來後先大喊一聲,呼叫notify方法 notify(); if (cnt <= 100) { System.out.println("執行緒" + Thread.currentThread().getName() + "中:cnt = " + cnt); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } cnt++; // 當前執行緒列印完畢一個整數後,為了防止繼續列印下一個資料,則呼叫wait方法 try { wait(); // 當前執行緒進入阻塞狀態,自動釋放物件鎖,必須在鎖定的程式碼中呼叫 } catch (InterruptedException e) { e.printStackTrace(); } } else { break; } } } } public static void main(String[] args) { ThreadCommunicateTest tct = new ThreadCommunicateTest(); Thread t1 = new Thread(tct); t1.start(); Thread t2 = new Thread(tct); t2.start(); } }
八·執行緒池
(1)實現Callable介面
從Java5開始新增加建立執行緒的第三種方式為實現java.util.concurrent.Callable介面。
方法宣告 | 功能介紹 |
---|---|
V call() | 計算結果並返回 |
常用的方法如下:
(2)FutureTask類
java.util.concurrent.FutureTask類用於描述可取消的非同步計算,該類提供了Future介面的基本實 現,包括啟動和取消計算、查詢計算是否完成以及檢索計算結果的方法,也可以用於獲取方法呼叫 後的返回結果。
方法宣告 | 功能介紹 |
---|---|
FutureTask(Callable callable) | 根據引數指定的引用來建立一個未來任務 |
V get() | 獲取call方法計算的結果 |
(3)執行緒池的由來
在伺服器程式設計模型的原理,每一個客戶端連線用一個單獨的執行緒為之服務,當與客戶端的會話結束 時,執行緒也就結束了,即每來一個客戶端連線,伺服器端就要建立一個新執行緒。 如果訪問伺服器的客戶端很多,那麼伺服器要不斷地建立和銷燬執行緒,這將嚴重影響伺服器的性 能。
(4)概念和原理
執行緒池的概念:首先建立一些執行緒,它們的集合稱為執行緒池,當伺服器接受到一個客戶請求後,就 從執行緒池中取出一個空閒的執行緒為之服務,服務完後不關閉該執行緒,而是將該執行緒還回到執行緒池 中。 線上程池的程式設計模式下,任務是提交給整個執行緒池,而不是直接交給某個執行緒,執行緒池在拿到任務 後,它就在內部找有無空閒的執行緒,再把任務交給內部某個空閒的執行緒,任務是提交給整個執行緒 池,一個執行緒同時只能執行一個任務,但可以同時向一個執行緒池提交多個任務。
(5)相關類和方法
從Java5開始提供了執行緒池的相關類和介面:java.util.concurrent.Executors類和 java.util.concurrent.ExecutorService介面。
方法宣告 | 功能介紹 |
---|---|
static ExecutorService newCachedThreadPool() | 建立一個可根據需要建立新執行緒的 執行緒池 |
static ExecutorService newFixedThreadPool(int nThreads) | 建立一個可重用固定執行緒數的執行緒 池 |
static ExecutorService newSingleThreadExecutor() | 建立一個只有一個執行緒的執行緒池 |
其中Executors是個工具類和執行緒池的工廠類,可以建立並返回不同型別的執行緒池,常用方法如 下:
方法宣告 | 功能介紹 |
---|---|
void execute(Runnable command) | 執行任務和命令,通常用於執行Runnable |
Future submit(Callable task) | 執行任務和命令,通常用於執行Callable |
void shutdown() | 啟動有序關閉 |
public class ThreadCallableTest implements Callable { @Override public Object call() throws Exception { // 計算1 ~ 10000之間的累加和並列印返回 int sum = 0; for (int i = 1; i <= 10000; i++) { sum +=i; } System.out.println("計算的累加和是:" + sum); // 50005000 return sum; } public static void main(String[] args) { ThreadCallableTest tct = new ThreadCallableTest(); FutureTask ft = new FutureTask(tct); Thread t1 = new Thread(ft); t1.start(); Object obj = null; try { obj = ft.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("執行緒處理方法的返回值是:" + obj); // 50005000 } }
public class ThreadPoolTest { public static void main(String[] args) { // 1.建立一個執行緒池 ExecutorService executorService = Executors.newFixedThreadPool(10); // 2.向執行緒池中佈置任務 executorService.submit(new ThreadCallableTest()); // 3.關閉執行緒池 executorService.shutdown(); } }