通常,用并發結局的問題大體上可以分為“速度”和“設計可管理性”兩種。
頻繁的線程間切換
,有效的避免“阻塞
”問題;仿真
相關的問題。java中通常有兩種方式創建線程:
擴展java.lang.Thread類
public class taskT extends Thread{ public void run() { System.out.
實現java.lang.Runnable接口
public class taskR implements Runnable{ @Override public void run() { System.out.println("正在執行Runnable!"); } } public static void main(String[] args) { taskR r = new taskR(); Thread thread = new Thread(r); thread.start(); }
一旦創建一個新線程并開始執行,即調用start方法時,虛擬機中就又多一個進程,這個進程和原先的進程時并行的。
public class TaskR implements Runnable{ @Override public void run() { System.out.println("正在執行線程B!"); System.out.println("已經執行完線程B!"); }}public class test { public static void main(String[] args) { System.out.println("正在執行main函數111!"); TaskR b = new TaskR(); Thread threadB = new Thread(b); System.out.println("準備添加線程B!"); threadB.start(); System.out.println("繼續執行main函數222!");// for (int i = 0; i < 999999; i++);//延時代碼 System.out.println("正在執行main函數333!"); }}
如上程序執行結果輸出如下:
正在執行main函數111!準備添加線程B!繼續執行main函數222!正在執行main函數333!正在執行線程B!已經執行完線程B!
將main函數的注釋代碼去除注釋,增加代碼延時,輸出如下:
正在執行main函數111!準備添加線程B!繼續執行main函數222!正在執行線程B!已經執行完線程B!正在執行main函數333!
由上兩組對比不難發現,當線程threadB一旦開始執行(執行threadbB.start()),main函數這條線程和線程threadB是并發的。
另外需要注意的是,多線程表面上給人的感覺是多個任務同時進行,實際上并非如此,虛擬機通過頻繁的切換進程來給人同時執行的錯覺。
2.線程狀態的轉換線程的狀態是線程控制的基礎。線程狀態總的可以分為五大類:生、等待、阻塞、睡眠、死。
當多個線程同時訪問互斥(可交換)數據時,應該同步以保護數據,確保兩個線程不會同時更改它。通常用synchronized字段實現,而且只能同步方法或同步代碼快。
如果兩個線程要執行一個類中的synchronized方法,并且兩個線程使用相同的實例來調用方法,那么一次只能有一個線程能夠執行方法,另一個需要等待,直到鎖被釋放。
4.線程的交換合并:join():join()方法是是在某個線程a中,加入一個線程b,線程b沒執行完前,a不得執行。
public class TaskR implements Runnable{ @Override public void run() { System.out.println("正在執行線程B!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("已經執行完線程B!"); } } public class test { public static void main(String[] args) throws InterruptedException { System.out.println("正在執行main函數!"); TaskR b = new TaskR(); Thread threadB = new Thread(b); System.out.println("準備添加線程B!"); threadB.start(); System.out.println("執行完main"); } } public class test2 { public static void main(String[] args) throws InterruptedException { System.out.println("正在執行main函數!"); TaskR b = new TaskR(); Thread threadB = new Thread(b); System.out.println("準備添加線程B!"); threadB.start(); System.out.println("threadB.join()"); threadB.join(); System.out.println("執行完main"); } }
分別執行test1和test2中的main執行結果如下:
正在執行main函數! 準備添加線程B! threadB.join() 執行完main 正在執行線程B! 已經執行完線程B!
test2中添加join()方法:
正在執行main函數! 準備添加線程B! threadB.join() 正在執行線程B! 已經執行完線程B! 執行完main
在threadB中調用sleep是為了讓main函數這條線程獲得執行機會。有結果,可知當threadB調用join方法后,即使sleep了main函數都不能跑完,說明join方法的作用,即必須threadB執行完才能繼續執行main函數。
java.util.concurrent.Executors。 例:
ExecutorService pool = Executors.newFixedThreadPool(2);Thread t1 = new MyThread(); Thread t2 = new MyThread();Thread t3 = new MyThread();Thread t4 = new MyThread();pool.execute(t1);pool.execute(t2);pool.execute(t3);pool.execute(t4);pool.shutdown();
|
新聞熱點
疑難解答