每篇一句 :不要只看到艱難,要看艱難後面的勝利php
初學心得: 勇於嘗試,就等於你已經向成功邁出了第一步html
(筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-20| JAVA 多線程 ]java
1.什麼是進程git
程序是指令和數據的有序的集合,其自己沒有任何運行的含義,是一個靜態的概念github
進程是一個具備必定獨立功能的程序,一個實體編程
幾乎全部的操做系統都支持同時運行多個任務,一個任務一般就是一個程序,每一個運行中的程序就是一個進程緩存
當一個程序運行時,內部可能包含了多個順序執行流,每一個順序執行流就是一個線程安全
2.進程的狀態: 進程執行時的間斷性,決定了進程可能具備多種狀態,事實上,運行中的進程具備多線程
如下三種基本狀態:併發
1.就緒狀態(Ready)
2.運行狀態(Running)
3.阻塞狀態(Blocked)
3.線程
線程其實是進程基礎之上的進一步劃分,一個進程啓動以後,裏面的若干程序,又能夠劃分紅若干個線程
線程:是進程中的一個執行路徑,共享一個內存空間,線程之間能夠自由切換
併發執行,一個進程最少有一個線程(單線程程序)
4.線程實現的兩種方式
在java中若是想要實現多線程操做,兩種實現方法
1.一種是繼承Thrcad類
2.另外一種是實現Runnable接口
5.多線程編程的優點
進程間不能共享內存,但線程之間共享內存很是容易
系統建立進程須要爲該進程從新分配系統資源,但建立線程則代價小得多,所以使用多線程來實現多任務併發比多進程的效率高
Java語言內置的多線程功能支持,而不是單純地做爲底層操做系統的調度方式,從而簡化了Java的多線程編程
(1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就是表明了線程須要完成的任務
所以,咱們常常把run方法稱爲線程執行體
(2)建立Thread子類的實例,即建立了線程對象
(3)調用線程對象的start方法來啓動該線程
(4)join線程:Thread提供了讓一個線程等待另外一個線程完成的方法:join() 方法
當在某個程序執行流中調用其餘線程的join()方法時,調用線程將被阻塞,直到被join方法加入的join線程完成爲止
join()方法一般由使用線程的程序調用,以將大問題劃分紅許多小問題,每一個小問題分配一個線程。當全部的小問題都獲得處理後,再調用主線程來進一步操做
(1)定義Runnable接口的實現類,並重寫該接口的run方法,該run方法的方法體一樣是該線程的線程執行體
(2)建立Runnable實現類的實例,並以此實例做爲Thread的target來建立Thread對象,該Thread對象纔是真正的線程對象
(3)調用線程對象的start方法來啓動該線程
若是咱們須要讓當前正在執行的線程暫停一段時間,並進入阻塞狀態
則能夠經過調用Thread類的靜態sleep方法,sleep方法有兩種重載的形式:
static void sleep(long millis):讓當前正在執行的線程暫停millis毫秒,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準確度的影響
static void sleep(long millis, int nanos):讓當前正在執行的線程暫停millis毫秒加nanos毫微妙,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準確度的影響
採用實現Runnable接口方式的多線程:
線程類只是實現了Runnable接口,還能夠能夠繼承其餘類
在這種方式下,能夠多個線程共享同一個target對象,因此很是適合多個相同線程來處理同一份資源的狀況
從而能夠將CPU,代碼和數據分開,造成清晰的模型,較好地體現了面向對象的思想
劣勢:編程稍稍複雜,若是須要訪問當前線程,必須使用Thread.currentThread()方法
採用繼承Thread類方式的多線程:
劣勢:由於線程類已經繼承了Thread類,因此不能再繼承其餘父類
優點:編寫簡單,若是須要訪問當前線程,無需使用Thread.currentThread()方法,直接使用this便可得到當前線程
線程聲明週期:
就緒狀態
執行狀態
阻塞狀態
多條線程併發修改共享資源就容易引起線程安全問題
使用同步解決多線程共享數據出現安全問題
多個線程有可能同時處理同一個資源
線程同步就是指多個線程在同一個時間段內只能有一個線程執行指定代碼
其餘線程等待此線程完成以後才能夠繼續執行
同步代碼塊synchronized(要同步對象){要同步的操做}
同步方法public synchronized void method(){要同步的操做}
同步代碼會帶來性能下降的問題,提升數據的安全性,犧牲性能來保證安全
同步代碼塊
Java的多線程支持引入了同步監視器來解決這個問題,使用同步監視器的通用方法就是同步代碼塊
synchronized後括號裏的obj就是同步監視器,上面代碼的含義是:線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定
同步方法
Java的多線程安全支持還提供了同步方法,同步方法就是使用synchronized關鍵字來修飾某個方法,則該方法成爲同步方法
對於同步方法而言,無需顯式指定同步監視器,同步方法的同步監視器是this,也就是該對象自己
線程死鎖
過多的同步有可能死鎖,死鎖的操做通常是在程序運行的時候纔有可能出現
多線程中要進行資源的共享,就須要同步,但同步過多,就可能形成死鎖
1.package cn.jeep; 2.//繼承Thread類 3.public class XianChengDemo extends Thread{ 4. private int i;//私有成員屬性 5. //重寫run方法,run方法的方法體就是線程執行體 6. public void run(){ 7. for(;i<100;i++){ 8. //當線程類繼承Thread類時,直接使用this.及格獲取當前線程 9. //Thread對象的getNname()返回當前線程名字 10. //所以能夠直接調用getName方法返回當前線程名字 11. System.out.println(getName()+" "+i); 12. } 13. } 14. //主方法入口 15. public static void main(String[] args) { 16. for(int i=0;i<100;i++){ 17. //調用Thread的currenTread方法獲取當前線程 18. System.out.println(Thread.currentThread().getName()+" "+i); 19. if(i == 20){ 20. //建立並啓動第一個線程 21. new XianChengDemo().start(); 22. //建立並啓動第二個線程 23. new XianChengDemo().start(); 24. } 25. } 26. } 27.}
1.package cn.runnable; 2.//聲明一個類 3.public class RunnableDenmo implements Runnable{ 4. private int i;//私有屬性 5. //重寫run方法 6. public void run(){ 7. for(;i<100;i++){ 8. //當線程類實現Runnable接口時 9. //若是想獲取當前線程,只能用Thread.currentTread()方法 10. System.out.println(Thread.currentThread().getName()+" "+i); 11. } 12. } 13. //主方法 14. public static void main(String[] args) { 15. for(int i=0;i<100;i++){ 16. System.out.println(Thread.currentThread().getName()+" "+i); 17. if(i == 20){ 18. RunnableDenmo st = new RunnableDenmo(); 19. //經過new Thread(target,name)方法建立新線程 20. new Thread(st,"新線程1").start(); 21. new Thread(st,"新線程2").start(); 22. } 23. } 24. } 25.}
1.package cn.callable; 2.import java.util.concurrent.Callable; 3.import java.util.concurrent.FutureTask; 4.public class CallableDemo { 5. public static void main(String[] args) { 6. //建立Callable對象 7. @SuppressWarnings("unused") 8. CallableDemo cl = new CallableDemo(); 9. //先使用Lambda表達式建立Callable<Integer>對象 10. //使用FutureTask來包裝Callable對象 11. FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{ 12. int i = 0; 13. for(;i<100;i++){ 14. System.out.println(Thread.currentThread().getName()+"的循環變量的i的值:"+i); 15. } 16. //call()方法能夠有返回值 17. return i; 18. }); 19. for(int i=0;i<100;i++){ 20. if(i==20){ 21. //實質仍是以Callable對象來建立並啓動線程 22. new Thread(task,"有返回值得線程").start(); 23. } 24. } 25. try{ 26. //獲取線程返回值 27. System.out.println("子線程的返回值:"+task.get()); 28. }catch(Exception ex){ 29. ex.printStackTrace(); 30. } 31. } 32.}
每篇一句 :不要只看到艱難,要看艱難後面的勝利
初學心得: 勇於嘗試,就等於你已經向成功邁出了第一步
(筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-20| JAVA 多線程 ]
1.什麼是進程
程序是指令和數據的有序的集合,其自己沒有任何運行的含義,是一個靜態的概念
進程是一個具備必定獨立功能的程序,一個實體
幾乎全部的操做系統都支持同時運行多個任務,一個任務一般就是一個程序,每一個運行中的程序就是一個進程
當一個程序運行時,內部可能包含了多個順序執行流,每一個順序執行流就是一個線程
2.進程的狀態: 進程執行時的間斷性,決定了進程可能具備多種狀態,事實上,運行中的進程具備
如下三種基本狀態:
1.就緒狀態(Ready)
2.運行狀態(Running)
3.阻塞狀態(Blocked)
3.線程
線程其實是進程基礎之上的進一步劃分,一個進程啓動以後,裏面的若干程序,又能夠劃分紅若干個線程
線程:是進程中的一個執行路徑,共享一個內存空間,線程之間能夠自由切換
併發執行,一個進程最少有一個線程(單線程程序)
4.線程實現的兩種方式
在java中若是想要實現多線程操做,兩種實現方法
1.一種是繼承Thrcad類
2.另外一種是實現Runnable接口
5.多線程編程的優點
進程間不能共享內存,但線程之間共享內存很是容易
系統建立進程須要爲該進程從新分配系統資源,但建立線程則代價小得多,所以使用多線程來實現多任務併發比多進程的效率高
Java語言內置的多線程功能支持,而不是單純地做爲底層操做系統的調度方式,從而簡化了Java的多線程編程
(1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就是表明了線程須要完成的任務
所以,咱們常常把run方法稱爲線程執行體
(2)建立Thread子類的實例,即建立了線程對象
(3)調用線程對象的start方法來啓動該線程
(4)join線程:Thread提供了讓一個線程等待另外一個線程完成的方法:join() 方法
當在某個程序執行流中調用其餘線程的join()方法時,調用線程將被阻塞,直到被join方法加入的join線程完成爲止
join()方法一般由使用線程的程序調用,以將大問題劃分紅許多小問題,每一個小問題分配一個線程。當全部的小問題都獲得處理後,再調用主線程來進一步操做
(1)定義Runnable接口的實現類,並重寫該接口的run方法,該run方法的方法體一樣是該線程的線程執行體
(2)建立Runnable實現類的實例,並以此實例做爲Thread的target來建立Thread對象,該Thread對象纔是真正的線程對象
(3)調用線程對象的start方法來啓動該線程
若是咱們須要讓當前正在執行的線程暫停一段時間,並進入阻塞狀態
則能夠經過調用Thread類的靜態sleep方法,sleep方法有兩種重載的形式:
static void sleep(long millis):讓當前正在執行的線程暫停millis毫秒,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準確度的影響
static void sleep(long millis, int nanos):讓當前正在執行的線程暫停millis毫秒加nanos毫微妙,並進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準確度的影響
採用實現Runnable接口方式的多線程:
線程類只是實現了Runnable接口,還能夠能夠繼承其餘類
在這種方式下,能夠多個線程共享同一個target對象,因此很是適合多個相同線程來處理同一份資源的狀況
從而能夠將CPU,代碼和數據分開,造成清晰的模型,較好地體現了面向對象的思想
劣勢:編程稍稍複雜,若是須要訪問當前線程,必須使用Thread.currentThread()方法
採用繼承Thread類方式的多線程:
劣勢:由於線程類已經繼承了Thread類,因此不能再繼承其餘父類
優點:編寫簡單,若是須要訪問當前線程,無需使用Thread.currentThread()方法,直接使用this便可得到當前線程
線程聲明週期:
就緒狀態
執行狀態
阻塞狀態
多條線程併發修改共享資源就容易引起線程安全問題
使用同步解決多線程共享數據出現安全問題
多個線程有可能同時處理同一個資源
線程同步就是指多個線程在同一個時間段內只能有一個線程執行指定代碼
其餘線程等待此線程完成以後才能夠繼續執行
同步代碼塊synchronized(要同步對象){要同步的操做}
同步方法public synchronized void method(){要同步的操做}
同步代碼會帶來性能下降的問題,提升數據的安全性,犧牲性能來保證安全
同步代碼塊
Java的多線程支持引入了同步監視器來解決這個問題,使用同步監視器的通用方法就是同步代碼塊
synchronized後括號裏的obj就是同步監視器,上面代碼的含義是:線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定
同步方法
Java的多線程安全支持還提供了同步方法,同步方法就是使用synchronized關鍵字來修飾某個方法,則該方法成爲同步方法
對於同步方法而言,無需顯式指定同步監視器,同步方法的同步監視器是this,也就是該對象自己
線程死鎖
過多的同步有可能死鎖,死鎖的操做通常是在程序運行的時候纔有可能出現
多線程中要進行資源的共享,就須要同步,但同步過多,就可能形成死鎖
1.package cn.jeep;
2.//繼承Thread類
3.public class XianChengDemo extends Thread{
4. private int i;//私有成員屬性
5. //重寫run方法,run方法的方法體就是線程執行體
6. public void run(){
7. for(;i<100;i++){
8. //當線程類繼承Thread類時,直接使用this.及格獲取當前線程
9. //Thread對象的getNname()返回當前線程名字
10. //所以能夠直接調用getName方法返回當前線程名字
11. System.out.println(getName()+" "+i);
12. }
13. }
14. //主方法入口
15. public static void main(String[] args) {
16. for(int i=0;i<100;i++){
17. //調用Thread的currenTread方法獲取當前線程
18. System.out.println(Thread.currentThread().getName()+" "+i);
19. if(i == 20){
20. //建立並啓動第一個線程
21. new XianChengDemo().start();
22. //建立並啓動第二個線程
23. new XianChengDemo().start();
24. }
25. }
26. }
27.}1.package cn.runnable;
2.//聲明一個類
3.public class RunnableDenmo implements Runnable{
4. private int i;//私有屬性
5. //重寫run方法
6. public void run(){
7. for(;i<100;i++){
8. //當線程類實現Runnable接口時
9. //若是想獲取當前線程,只能用Thread.currentTread()方法
10. System.out.println(Thread.currentThread().getName()+" "+i);
11. }
12. }
13. //主方法
14. public static void main(String[] args) {
15. for(int i=0;i<100;i++){
16. System.out.println(Thread.currentThread().getName()+" "+i);
17. if(i == 20){
18. RunnableDenmo st = new RunnableDenmo();
19. //經過new Thread(target,name)方法建立新線程
20. new Thread(st,"新線程1").start();
21. new Thread(st,"新線程2").start();
22. }
23. }
24. }
25.}1.package cn.callable;
2.import java.util.concurrent.Callable;
3.import java.util.concurrent.FutureTask;
4.public class CallableDemo {
5. public static void main(String[] args) {
6. //建立Callable對象
7. @SuppressWarnings("unused")
8. CallableDemo cl = new CallableDemo();
9. //先使用Lambda表達式建立Callable<Integer>對象
10. //使用FutureTask來包裝Callable對象
11. FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
12. int i = 0;
13. for(;i<100;i++){
14. System.out.println(Thread.currentThread().getName()+"的循環變量的i的值:"+i);
15. }
16. //call()方法能夠有返回值
17. return i;
18. });
19. for(int i=0;i<100;i++){
20. if(i==20){
21. //實質仍是以Callable對象來建立並啓動線程
22. new Thread(task,"有返回值得線程").start();
23. }
24. }
25. try{
26. //獲取線程返回值
27. System.out.println("子線程的返回值:"+task.get());
28. }catch(Exception ex){
29. ex.printStackTrace();
30. }
31. }
32.}
1.package cn.tongbu; 2.public class TB { 3. public static void main(String[] args) { 4. TbDemo tb = new TbDemo(); 5. Thread t1 = new Thread(tb,"小明"); 6. Thread t2 = new Thread(tb,"小白"); 7. Thread t3 = new Thread(tb,"小紅"); 8. Thread t4 = new Thread(tb,"小黑"); 9. Thread t5 = new Thread(tb,"小華"); 10. t1.start(); 11. t2.start(); 12. t3.start(); 13. t4.start(); 14. t5.start(); 15. } 16.} 17.class TbDemo implements Runnable{ 18. Object obj = new Object();//同步得標記 19. @Override 20. public void run() { 21. //線程同步代碼塊 22. //synchronized(obj){ 23. //} 24. say();//調用同步方法 25. } 26. /** 27. * 同步方法 28. */ 29. public synchronized void say(){ 30. System.out.println(Thread.currentThread().getName()+"正在通話中...."); 31. try { 32. Thread.sleep(2000);//2秒 33. } catch (InterruptedException e) { 34. e.printStackTrace(); 35. } 36. System.out.println(Thread.currentThread().getName()+"通話結束!"); 37. } 38.}
1.package cn.sisuo; 2.public class SiSuoDemo { 3. public static void main(String[] args) { 4. new Ss(); 5. } 6.} 7.//警 8.class XingJing{ 9. //同步方法 10. public synchronized void say(FeiTu f){ 11. System.out.println("警方說先放人質,在實行抓捕"); 12. f.dos(); 13. } 14. public synchronized void dos(){ 15. System.out.println("贊成匪徒要求,在實行抓捕"); 16. } 17.} 18.//匪徒 19.class FeiTu{ 20. //同步方法 21. public synchronized void say(XingJing x){ 22. System.out.println("匪徒說先找一輛車,在放人質"); 23. x.dos(); 24. } 25. public synchronized void dos(){ 26. System.out.println("先找一輛車,再放人質"); 27. } 28.} 29./** 30. * 死鎖線程 31. * @author JEEP-711 32. * 33. */ 34.class Ss implements Runnable{ 35. XingJing xj = new XingJing(); 36. FeiTu ft = new FeiTu(); 37. //模擬線程死鎖構造方法 38. public Ss(){ 39. new Thread(this).start();//爲了快速實現 40. ft.say(xj); 41. } 42. @Override 43. public void run() { 44. xj.say(ft); 45. } 46.}
1.package cn.chinabank;//中國銀行包 2.//聲明一個帳戶類 3.public class Account { 4. private String name;//私有屬性-姓名 5. private double number=0.0;//私有屬性-餘額 6. //構造方法並傳值 7. public Account(String name,double number){ 8. this.name = name;//當前姓名 9. this.number = number;//當前金額 10. } 11. //取得getName方法 12. public String getName() { 13. return name; 14. } 15. //設置setName方法 16. public void setName(String name) { 17. this.name = name; 18. } 19. //取得getNumber方法 20. public double getNumber() { 21. return number; 22. } 23. //設置setNumber方法 24. public void setNumber(double number) { 25. this.number = number; 26. } 27.}
1.package cn.chinabank;//中國銀行包 2.import java.util.Scanner; 3.//聲明一箇中國銀行類 4.public class ChinaBank { 5. //定義主方法 6. public static void main(String[] args) { 7. @SuppressWarnings("resource") 8. Scanner sc = new Scanner(System.in);//接收控制檯鍵盤輸入 9. System.out.println("----------------------"); 10. System.out.println("----歡迎您進入中國銀行-----"); 11. System.out.println("---請選擇您須要辦理的業務---"); 12. System.out.println("1.存款"+"\t"+" 2.取款"+"\t"+"3.退出"); 13. System.out.println("----------------------"); 14. int sr = sc.nextInt();//接收一個數 15. //接收用戶輸入 16. switch(sr){ 17. //輸入1則進入存款功能 18. case 1: 19. System.out.println("請您輸入存款金額:");//提示用戶存款金額 20. double number = sc.nextDouble();//接收用戶輸入金額 21. @SuppressWarnings("unused") 22. Account account1 = new Account("asdd",number);//建立Accound對象 23. System.out.println("請您將鈔票疊整齊後放入存鈔口..");//提示用戶將鈔票放入存鈔口 24. try{ 25. Thread.sleep(2000);//模仿現實銀行存鈔,設置睡眠時間兩秒 26. System.out.println("正在存鈔,請稍後...");//將輸出等待 27. Thread.sleep(4000);//將其過程等待四秒 28. System.out.println("存款成功!");//則輸出存款成功 29. System.out.println("您的存款金額爲:"+number+"\t"+"當前帳戶餘額爲:"+number); 30. //輸出存款金額 31. System.out.println("1.是否打印憑條"+"\t"+"2.是否繼續存款"+"\t"+"3.退出"); 32. //用戶繼續選擇 33. int sr1 = sc.nextInt();//接收用戶輸入 34. switch(sr1){ 35. //接收用戶是否打印憑條 36. case 1: 37. System.out.println("dce"); 38. System.out.println("打印完成,退出打印"); 39. break; 40. //接收用戶是否繼續存款 41. case 2: 42. System.out.println("繼續存款"); 43. banking(); 44. break; 45. //接收用戶退出 46. case 3: 47. System.out.println("您已退出存款選項"); 48. break; 49. //防止隨意輸入 50. default : 51. System.out.println("您輸入有誤,請從新輸入"); 52. break; 53. } 54. }catch(Exception e){ 55. e.printStackTrace(); 56. } 57. break; 58. //輸入2則進入取款功能 59. case 2:System.out.println("請輸出您的取款金額:"); 60. Account account2 = new Account("小明",7000);//建立Account對象並傳參數 61. DrawMoney ka = new DrawMoney(account2,3000);//建立銀行卡取款3000元 62. DrawMoney zhe = new DrawMoney(account2,4000);//建立存摺取款2000元 63. new Thread(ka).start();//開啓銀行卡線程 64. new Thread(zhe).start();//開啓存摺線程 65. break; 66. //輸入3則退出銀行系統 67. case 3: 68. System.out.println("您已安全退出中國銀行系統,感謝您的光臨!"); 69. System.exit(0);//退出指令 70. break; 71. //防止用戶隨意輸入則進行友情提示 72. default : 73. System.out.println("您輸入有誤,請從新輸入"); 74. break; 75. } 76. } 77. //繼承存款金額 78. public static void banking(){ 79. @SuppressWarnings("resource") 80. Scanner sc2 = new Scanner(System.in);//接收控制檯鍵盤輸入 81. System.out.println("請您輸入存款金額:");//提示用戶存款金額 82. double number = sc2.nextDouble();//接收用戶輸入金額 83. @SuppressWarnings("unused") 84. Account account2 = new Account("asdd",number);//建立Accound對象 85. System.out.println("請您將鈔票疊整齊後放入存鈔口..");//提示用戶將鈔票放入存鈔口 86. try{ 87. Thread.sleep(2000);//模仿現實銀行存鈔,設置睡眠時間兩秒 88. System.out.println("正在存鈔,請稍後...");//將輸出等待 89. Thread.sleep(4000);//將其過程等待四秒 90. System.out.println("存款成功!");//則輸出存款成功 91. System.out.println("您的存款金額爲:"+number+"\t"+"當前帳戶餘額爲:"+number); 92. //輸出存款金額 93. System.out.println("1.是否打印憑條"+"\t"+"\t"+"2.退出");//用戶繼續選擇 94. int sr3 = sc2.nextInt();//接收用戶輸入 95. switch(sr3){ 96. //接收用戶是否打印憑條 97. case 1: 98. System.out.println("dce"); 99. System.out.println("打印完成,退出打印"); 100. break; 101. case 2: 102. System.out.println("您已退出存款選項"); 103. break; 104. //防止隨意輸入 105. default : 106. System.out.println("您輸入有誤,請從新輸入"); 107. break; 108. } 109. }catch(Exception e){ 110. e.printStackTrace(); 111. } 112. } 113.}
1.package cn.chinabank;//中國銀行包 2.//取錢類實現Runnable接口 3.public class DrawMoney implements Runnable{ 4. private Account account;//私有屬性-帳戶 5. private double money;//私有屬性-金額 6. //構造方法並傳值 7. public DrawMoney(Account account,double money){ 8. this.account = account;//當前帳戶 9. this.money = money;//當前金額 10. } 11. @Override 12. public void run() { 13. while(true){ 14. //線程同步塊 15. //至關於將account隊形鎖住,只有執行完代碼塊,才能夠釋放,其餘線程才能拿到 16. //account必須是同一個 17. synchronized(account){ 18. //若是帳戶金額大於等於金額 19. if(account.getNumber()>=money){ 20. account.setNumber(account.getNumber()-money);//帳戶餘額減去取款金額 21. //輸出取款成功,並顯示當前帳戶剩餘金額 22. System.out.println("你已取款成功,您取款金額爲:"+money+"元,剩餘金額爲:"+account.getNumber()+"元"); 23. //異常處理 24. try{ 25. Thread.sleep(2000);//調用方法設置睡眠兩秒 26. }catch(InterruptedException e){ 27. e.printStackTrace(); 28. } 29. //不然提示取款不成功,顯示當前帳戶餘額 30. }else{ 31. System.out.println("對不起,您的帳戶餘額不足,您當前帳戶餘額剩餘"+account.getNumber()+"元");//輸出帳戶金額 32. } 33. } 34. break; 35. } 36. }
多線程的開發中有一個最經典的操做案例,就是生產者-消費者
生產者不斷生產產品,消費者不斷取走產品1./** 2.* 生產者與消費者應用案例 3.* sleep與wait區別 4.* sleep讓當前的線程進入休眠狀態,讓出cpu,讓其餘線程執行 5.* 若是用同步的話,有對象鎖的時候,是不會釋放的,只能等待此線程使用完,纔可使用 6.* wait會釋放對象鎖,必須等待其餘線程喚醒 7.* @author JEEP-711 8.* 9.*/ 10.public class ScXf { 11. public static void main(String[] args) { 12. Phones p = new Phones(null, null);//建立Phones對象 13. PhoneSc s = new PhoneSc(p);//建立PhoneSc對象 14. PhoneXf x = new PhoneXf(p);//建立PhoneXf對象 15. new Thread(s).start();//啓動生產者線程 16. new Thread(x).start();//啓動消費者線程 17. } 18.} 19./** 20. * 手機生產者,單獨的生產者,實現Runnable接口 21. * @author JEEP-711 22. * 23. */ 24.class PhoneSc implements Runnable{ 25. private Phones phones; 26. public PhoneSc(Phones phones){ 27. this.phones = phones; 28. } 29. @Override 30. public void run() { 31. //不斷地生產20份,生產的過程 32. for (int i = 0; i < 50; i++) { 33. if(i%2==0){ 34. phones.set("金立手機", "金立手機,中國造!"); 35. }else{ 36. phones.set("小米手機", "小米手機,爲發燒而生!"); 37. } 38. } 39. } 40.} 41./** 42.* 手機消費者,顧客 43. * @author JEEP-711 44. * 45. */ 46.class PhoneXf implements Runnable{ 47. private Phones phones; 48. public PhoneXf(Phones phones){ 49. this.phones = phones; 50. } 51. @Override 52. public void run() { 53. for (int i = 0; i < 50; i++) { 54. phones.get();//調用消費產品方法 55. } 56. } 57.} 58./** 59.* 產品的對象,生產的手機 60.* @author JEEP-711 61.* 62. */ 63.class Phones{ 64. @Override 65. public String toString() { 66. return "Phones [name=" + name + ", content=" + content + "]"; 67. } 68. private String name; 69. private String content; 70. /**true表示能夠生產,false表示能夠消費 71. * 做爲標記,如何flag等於true表示能夠生產,如何flag等於false表示不可生產 72. * 若是flag等於false表示能夠消費狀態,能夠取走,flag等於true表示不能取走 73. * 解決重複值得問題 74. */ 75. private boolean flag = true;//表示能夠生產,false表示能夠消費 76. //構造方法 77. public Phones(String name, String content) { 78. super(); 79. this.name = name; 80. this.content = content; 81. } 82. //取得名稱方法 83. public String getName() { 84. return name; 85. } 86. //設置名稱方法 87. public void setName(String name) { 88. this.name = name; 89. } 90. //取得內容方法 91. public String getContent() { 92. return content; 93. } 94. //設置內容方法 95. public void setContent(String content) { 96. this.content = content; 97. } 98. /** 99. * 經過同步,解決了取值錯誤問題 100. * @param name 101. * @param content 102. */ 103. //生產製造同步方法 104. public synchronized void set(String name, String content){ 105. if(!flag){ 106. try { 107. //調用該方法,當前線程進入等待池等待狀態,沒有指定時間, 108. //須要其餘線程喚醒,釋放對象鎖,讓出cpu 109. this.wait(); 110. } catch (InterruptedException e) { 111. e.printStackTrace(); 112. } 113. } 114. this.setName(name); 115. try { 116. Thread.sleep(300); 117. } catch (InterruptedException e) { 118. e.printStackTrace(); 119. } 120. this.setContent(content); 121. flag = false;//表示能夠消費,取走 122. this.notify();//喚醒在該監視器上的一個線程 123. } 124. //消費產品同步取值方法 125. public synchronized void get(){ 126. if(flag){ 127. try { 128. //調用該方法,當前線程進入等待池等待狀態,沒有指定時間, 129. //須要其餘線程喚醒,釋放對象鎖,讓出cpu 130. this.wait(); 131. } catch (InterruptedException e) { 132. e.printStackTrace(); 133. } 134. } 135. try { 136. Thread.sleep(300); 137. } catch (InterruptedException e) { 138. e.printStackTrace(); 139. } 140. System.out.println(this.getName()+":"+this.getContent()); 141. flag = true; 142. this.notify(); 143. } 144.}
線程池是預先建立線程的一種技術,線程池在尚未任務到來以前,建立必定數量的線程,放入空閒隊列中,而後對這些資源進行復用,減小頻繁的建立和銷燬對象
java裏面線程池的頂級接口是Executor,是一個執行線程的工具
線程池接口是ExecutorServise
1.java.util.concurrent包:併發編程中很經常使用的實用工具包
2.Executor接口:執行已提交Runnable任務的對象ExecutorService接口:
Executor提供了管理終止的方法,以及可能爲跟蹤一個或
多個異步任務執行情況而發生的Future的方法
Executors類:此包中所定義的Executor、ExecutorService等的工廠和實現方法
在Executors類裏提供了一些靜態工廠,生成一些經常使用的線程池
newSingleThreadExecutor:
建立一個單線程的線程池,這個線程池只有一個線程在工做,也就是至關於單線程
串行執行全部的任務,若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它,此線程池保證全部任務的執行順序按照任務的提交順序執行
newFixedThreadPool:
建立固定大小的線程池,每次提交一個任務就建立一個線程,直到線程達到線程池的最大線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程
newCacheadThreadPool:
建立一個可緩存的線程池,若是線程池的大小超過了處理任務所須要的線程,那麼就會回收部分空閒(60秒不執行)的線程,當任務數增長時,此線程池又能夠智能的添加新線程來處理任務,此線程池不會對線程池大小作限制,線程池大小徹底依賴於操做系統(或者說jvm)可以建立的最大線程大小
newSchediledThreadPool:
建立一個大小無限制的線程池,此線程池支持定時以及週期性執行任務需求使用線程池的步驟:
(1)調用Executors類的靜態工廠方法建立一個ExecutorService對象或ScheduledExecutorService對象,其中前者表明簡單的線程池,後者表明能以任務調度方式執行線程的線程池
(2)建立Runnable實現類或Callable實現類的實例,做爲線程執行任務
(3)調用ExecutorService對象的submit方法來提交Runnable實例或Callable實例;或調用ScheduledExecutorService的schedule來執行線程
(4)當不想提交任何任務時調用ExecutorService對象的shutdown方法來關閉線程池
FaceBook:JEEP SevenEleven
Twitter:@JEEP7ll
新浪官方微博: @JEEP-711
Blog Garden:http://www.cnblogs.com/JEEP711/
W3C/Blog:http://www.w3cschool.cn/jeep711blog/
CSDN/Blog:http://blog.csdn.net/jeep911
51CTO/Blog:http://jeep711.blog.51cto.com/