java進階(37)--多線程

文檔目錄:html

1、進程與線程java

2、多線程的實現安全

3、獲取線程名與線程對象多線程

4、線程sleep方法併發

5、線程調度與優先級ide

6、線程安全(重點)this

7、死鎖spa

---------------------------------------分割線:正文--------------------------------------------------------線程

1、進程與線程調試

一、基本概念

進程是一個應用程序。

線程是一個進程中的執行場景/執行單元。

一個進程能夠啓動多個線程

 

二、舉例說明進程與線程、

java輸出helloworld回車,先啓動JVM是一個進行,JVM再啓動一個主線程調用main方法,同時再啓動一個垃圾回收線程負責看護,回收垃圾,至少兩個線程併發。

 

三、進程與線程的關係

阿里巴巴:進程A

馬雲:阿里巴巴的一個線程

張小龍:阿里巴巴的一個線程

京東:進程B

強東:jd的一個線程

奶茶:jd的一個吸納還曾

進程A與B內存獨立不共享(阿里與jd資源不共享)

線程A與線程B:JAVA中堆內存與方法區內存共享,棧內存獨立

 

四、多線程機制的目的

提升程序的處理效率

 

2、多線程的實現

一、第一種實現方式:繼承java.lang.Thread方法,並從新run方法

 1 package JAVAADVANCE;  2 public class TestAdvance37TestThread01 {  3     //這裏是main方法,這裏的代碼屬於主線程,在主線程中運行
 4     public static void main(String[] args) {  5         //新建一個分支線程對象,
 6        MyThread myThread=new MyThread();  7        //start開啓新的棧空間,啓動一個分支線程,啓動成功線程自動調用run方法,而直接調用MyThread.run()不會啓動多線程
 8  myThread.start();  9         //這裏的代碼運行在主線程中
10         for (int i=0;i<100;i++){ 11             System.out.println("主線程------->"+i); 12  } 13  } 14 } 15 class MyThread extends Thread{ 16  @Override 17     public void run() { 18     //編寫程序,這段代碼在分支線程中執行
19         for(int i=0;i<100;i++){ 20             System.out.println("分支線程------->"+i); 21  } 22  } 23 }

查看執行結果片斷:主線程與分支線程是併發的

1 主線程------->91
2 主線程------->92
3 分支線程------->0
4 主線程------->93
5 分支線程------->1
6 主線程------->94
7 主線程------->95

二、第二種實現方式:編寫一個類,實現java.lang.Runnable接口,實現run方法(建議使用,由於此類還能夠繼承其餘方法)

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread02 {  4     public static void main(String[] args) {  5         //建立線程對象,將可運行的對象封裝成線程對象
 6         Thread t = new Thread(new MyRunnable());  7  t.start();  8         //這裏的代碼運行在主線程中
 9         for (int i = 0; i < 100; i++) { 10             System.out.println("主線程------->" + i); 11  } 12  } 13 } 14 class MyRunnable implements Runnable{ 15  @Override 16     public void run() { 17         for(int i=0;i<100;i++){ 18             System.out.println("分支線程------->"+i); 19  } 20  } 21 }

查看執行結果片斷:主線程與分支線程是併發的

1 分支線程------->54
2 主線程------->4
3 主線程------->5
4 分支線程------->55
5 主線程------->6
6 主線程------->7

三、第三種實現方式:採用匿名內部類方法

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread03 {  4     public static void main(String[] args) {  5         Thread t = new Thread(new Runnable() {  6  @Override  7             public void run() {  8                 for (int i = 0; i < 100; i++) {  9                     System.out.println("分支線程------->" + i); 10  } 11  } 12  }); 13         //啓動分支線程
14  t.start(); 15         for (int i = 0; i < 100; i++) { 16             System.out.println("主線程------->" + i); 17  } 18  } 19 }

查看執行結果片斷:主線程與分支線程是併發的

1 分支線程------->10
2 主線程------->12
3 分支線程------->11
4 主線程------->13
5 分支線程------->12
6 主線程------->14
7 分支線程------->13

四、第四種實現方式:實現callable接口(JDK8新特性) 

(1)優先與缺點:

優勢:能夠拿到線程的執行結果

缺點:效率比較低,獲取結果時,當前線程受阻塞

(2)實現方式

 1 package JAVAADVANCE;  2 
 3 import java.util.concurrent.Callable;  4 import java.util.concurrent.ExecutionException;  5 import java.util.concurrent.Future;  6 import java.util.concurrent.FutureTask;  7 
 8 public class TestAdvance37TestThread10 {  9     public static void main(String[] args) { 10         //建立一個將來任務對象,須要黑一個callable接口實現類的對象,這裏使用匿名內部類
11         FutureTask task=new FutureTask(new Callable() { 12  @Override 13             public Object call() throws Exception { 14                 //call()相似run方法,可是有返回值 15                 //模擬行爲
16                 System.out.println("call method begin"); 17                 Thread.sleep(1000*10); 18                 System.out.println("call method end"); 19                 int a=100; 20                 int b=200; 21                 return a+b; //自動裝箱,300結果變爲Integer
22  } 23  }); 24         //建立線程對象
25         Thread t=new Thread(task); 26         //啓動線程
27  t.start(); 28         //獲取t線程的返回結果
29         try { 30             Object obj=task.get(); 31             System.out.println("線程的執行結果爲:"+obj); 32         } catch (InterruptedException e) { 33  e.printStackTrace(); 34         } catch (ExecutionException e) { 35  e.printStackTrace(); 36  } 37         //main方法這裏的程序要想執行必須等待get方法
38         System.out.println("hello world"); 39 
40  } 41 }

查看執行結果:hello world在10秒後展現

call method begin call method end 線程的執行結果爲:300 hello world

 

3、獲取線程名與線程對象

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread04 {  4     public static void main(String[] args) {  5         //獲取當前線程對象
 6         Thread t1=Thread.currentThread();  7         System.out.println("main方法下的當前線程名:"+t1.getName());  8         MyThread t2=new MyThread();  9         //查看線程默認名
10         System.out.println("線程默認名:"+t2.getName()); 11         t2.setName("ttttt"); 12         System.out.println("修改後的線程名:"+t2.getName()); 13  } 14 }

查看執行結果

main方法下的當前線程名:main 線程默認名:Thread-0 修改後的線程名:ttttt

 

4、線程sleep方法

一、概念:

(1)sleep爲靜態方法

(2)參數爲毫秒

(3)做用:讓當前線程進入休眠,進入"阻塞狀態",放棄佔用cpu時間片,讓給其餘線程使用

二、舉例說明sleep方法

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread05 {  4     public static void main(String[] args) {  5         //讓當前進程進入休眠狀態,睡眠5秒
 6         try {  7             Thread.sleep(1000*5);  8             System.out.println("hello world");  9         } catch (InterruptedException e) { 10  e.printStackTrace(); 11  } 12  } 13 }

5秒後控制檯打印hello world

三、停止進程的睡眠

 注:run()方法內只能try catch,不能throws,由於子類不能比父類拋出更多的異常

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread06 {  4     public static void main(String[] args) {  5         Thread t=new Thread(new MyRunnable2());  6         t.setName("t");  7  t.start();  8         try {  9             Thread.sleep(1000*5); 10         } catch (InterruptedException e) { 11  e.printStackTrace(); 12  } 13         //終於線程的睡眠
14  t.interrupt(); 15  } 16 } 17 
18 class MyRunnable2 implements Runnable{ 19  @Override 20     public void run() { 21         System.out.println(Thread.currentThread().getName()+"---->begin"); 22         try { 23             Thread.sleep(1000*60*60*24*365); 24         } catch (InterruptedException e) { 25  e.printStackTrace(); 26  } 27         System.out.println(Thread.currentThread().getName()+"----->end"); 28  } 29 }

查看運行結果:sleep5秒後出現異常信息,進程被停止

t---->begin java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at JAVAADVANCE.MyRunnable2.run(TestAdvance37TestThread06.java:23) at java.lang.Thread.run(Thread.java:748) t----->end Process finished with exit code 0

四、強行終止進程執行

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread07 {  4     public static void main(String[] args) {  5         Thread t=new Thread(new MyRunnable3());  6         t.setName("t");  7  t.start();  8         try {  9             Thread.sleep(1000*5); 10         } catch (InterruptedException e) { 11  e.printStackTrace(); 12  } 13  t.stop(); 14  } 15 } 16 
17 class MyRunnable3 implements Runnable{ 18  @Override 19     public void run() { 20         for(int i=0;i<10;i++){ 21             System.out.println(Thread.currentThread().getName()+"------>"+i); 22             try { 23                 Thread.sleep(1000); 24             } catch (InterruptedException e) { 25  e.printStackTrace(); 26  } 27  } 28  } 29 }

stop方法的缺點:容易丟失數據,直接將線程殺死

五、合理的終止一個線程的執行

 1 package JAVAADVANCE;  2 
 3 import static java.lang.Thread.sleep;  4 
 5 public class TestAdvance37TestThread08 {  6     public static void main(String[] args) {  7         MyRunnable4 r=new MyRunnable4();  8         Thread t=new Thread(r);  9         t.setName("t"); 10  t.start(); 11         try { 12             sleep(1000*5); 13         } catch (InterruptedException e) { 14  e.printStackTrace(); 15  } 16         //何時停止t改成false
17         r.run=false; 18  } 19 } 20 
21 class MyRunnable4 implements Runnable{ 22     //打一個布爾標記
23     boolean run=true; 24  @Override 25     public void run() { 26 
27             for(int i=0;i<10;i++){ 28             if(run){ 29                 System.out.println(Thread.currentThread().getName()+"----->"+i); 30                 try { 31                     sleep(1000); 32                 } catch (InterruptedException e) { 33  e.printStackTrace(); 34  } 35  } 36 
37         else { 38             //save保存代碼 39             //終止當前線程
40             return; 41  } 42  } 43  } 44 }

查看執行結果,5秒後執行結果。

t----->0 t----->1 t----->2 t----->3 t----->4

 

5、線程調度與優先級

一、分兩種:搶佔式調度模型與均分式調度模型,java屬於前者

二、經常使用方法:

(1)設置線程的優先級:void setPrority()

(2)獲取線程的優先級:int getPrority()

優先級分:1,5,10(最高)

(3)進程讓位:static void yield()

(4)合併線程程:t.join() //當前線程阻塞,t線程加入當前線程中

 

6、線程安全(重點)

參考下一個章節

 

7、死鎖

 一、含義:

不出現異常,也不會出現錯誤,程序僵持,難以調試

二、舉例:

 1 package JAVAADVANCE;  2 
 3 public class TestAdvance37TestThread09 {  4     public static void main(String[] args) {  5         Object o1=new Object();  6         Object o2=new Object();  7         Thread t1=new MyThread1(o1,o2);  8         Thread t2=new MyThread2(o1,o2);  9  t1.start(); 10  t2.start(); 11  } 12 } 13 class MyThread1 extends Thread{ 14  Object o1; 15  Object o2; 16     public MyThread1(Object o1,Object o2){ 17         this.o1=o1; 18         this.o2=o2; 19  } 20     public void run(){ 21         synchronized (o1){ 22             try { 23                 Thread.sleep(1000); 24             } catch (InterruptedException e) { 25  e.printStackTrace(); 26  } 27             synchronized (o2){} 28  } 29  } 30 } 31 class MyThread2 extends Thread{ 32  Object o1; 33  Object o2; 34     public MyThread2(Object o1,Object o2){ 35         this.o1=o1; 36         this.o2=o2; 37  } 38     public void run(){ 39         synchronized (o2){ 40             try { 41                 Thread.sleep(1000); 42             } catch (InterruptedException e) { 43  e.printStackTrace(); 44  } 45             synchronized (o1){} 46  } 47  } 48 }

程序運行一直不會結束也沒有返回

三、解決方案:

程序編寫使用時儘可能避免synchronized 方法嵌套使用

相關文章
相關標籤/搜索