java線程之基礎學習總結(二)

 java線程之基礎學習總結(二)

 

首先解釋第一節中提到“不要調用Thread類或Runnable對象的run方法。直接調用run方法,只會執行同一個線程中的任務,而不會啓動新線程。應該調用Thread.start()方法。這個方法將創建一個執行run方法的新線程。”因爲run方法驅動的是main線程,不會啓動其他新線程。但是如果使用start()方法就可以啓動新線程,且默認優先級與main線程一樣。都是Thread.NORM_PRIORITY=5。就可出現搶佔資源的現象了!!!!!

實例: 

  1. public class RunStart implements Runnable { 
  2.         public void run() { 
  3.         for (int i = 0; i < 5; i++) { 
  4.             System.out.println(Thread.currentThread().getName() + "線程正運行  i="+ i); 
  5.         } 
  6.     } 

編寫TestRunStart類調用:

  1. public class TestRunStart { 
  2.     public static void main(String[] args) { 
  3.         RunStart runStart = new RunStart(); 
  4.         Thread thread1 = new Thread(runStart, "thread2"); 
  5.         Thread thread2 = new Thread(runStart, "thread2"); 
  6.         thread1.run(); 
  7.         thread2.run(); 
  8.     } 

運行結果:

  1. main線程正運行  i=0 
  2. main線程正運行  i=1 
  3. main線程正運行  i=2 
  4. main線程正運行  i=3 
  5. main線程正運行  i=4 
  6. main線程正運行  i=0 
  7. main線程正運行  i=1 
  8. main線程正運行  i=2 
  9. main線程正運行  i=3 
  10. main線程正運行  i=4 

TestRunStart類改一下如下:

  1. public class TestRunStart { 
  2.     public static void main(String[] args) { 
  3.         RunStart runStart = new RunStart(); 
  4.         Thread thread1 = new Thread(runStart); 
  5.         Thread thread2 = new Thread(runStart); 
  6.         thread1.start(); 
  7.         thread2.start(); 
  8.     } 

運行結果:

  1. Thread-0線程正運行  i=0 
  2. Thread-0線程正運行  i=1 
  3. Thread-0線程正運行  i=2 
  4. Thread-0線程正運行  i=3 
  5. Thread-0線程正運行  i=4 
  6. Thread-1線程正運行  i=0 
  7. Thread-1線程正運行  i=1 
  8. Thread-1線程正運行  i=2 
  9. Thread-1線程正運行  i=3 
  10. Thread-1線程正運行  i=4 

就是系統默認的名字了!!!

線程優先級: 

  1. public class PriorityTest { 
  2.     public static void main(String[] args) { 
  3.         System.out.println("Thread.MAX_PRIORITY : " + Thread.MAX_PRIORITY); 
  4.         System.out.println("Thread.NORM_PRIORITY: " + Thread.NORM_PRIORITY); 
  5.         System.out.println("Thread.MIN_PRIORITY : " + Thread.MIN_PRIORITY); 
  6.     } 

運行結果:

  1. Thread.MAX_PRIORITY : 10 
  2. Thread.NORM_PRIORITY: 5 
  3. Thread.MIN_PRIORITY : 1 

看看main線程的優先級:

  1. public class RunStart implements Runnable { 
  2.     public void run() { 
  3.         switch (Thread.currentThread().getPriority()) { 
  4.         case 1
  5.             System.out.println(Thread.currentThread().getName() 
  6.                     + "線程優先級:Thread.MIN_PRIORITY=" 
  7.                     + Thread.currentThread().getPriority()); 
  8.             break
  9.         case 5
  10.             System.out.println(Thread.currentThread().getName() 
  11.                     + "線程優先級:Thread.NORM_PRIORITY=" 
  12.                     + Thread.currentThread().getPriority()); 
  13.             break
  14.         case 10
  15.             System.out.println(Thread.currentThread().getName() 
  16.                     + "線程優先級:Thread.MAX_PRIORITY=" 
  17.                     + Thread.currentThread().getPriority()); 
  18.             break
  19.         default
  20.             System.out 
  21.                     .println(Thread.currentThread().getName() + "線程優先級:ERORR"); 
  22.             break
  23.         } 
  24.     } 

調用:

  1. public class TestRunStart { 
  2.     public static void main(String[] args) { 
  3.         RunStart runStart = new RunStart(); 
  4.         Thread thread1 = new Thread(runStart, "thread1"); 
  5.         thread1.run(); 
  6.     } 

運行結果:

  1. main線程優先級:Thread.NORM_PRIORITY=5 

看看創建新的線程的默認優先級:

  1. public class TestRunStart { 
  2.     public static void main(String[] args) { 
  3.         RunStart runStart = new RunStart(); 
  4.         Thread thread1 = new Thread(runStart, "singsong"); 
  5.         thread1.start(); 
  6.         } 

運行結果: 

  1. singsong線程優先級:Thread.NORM_PRIORITY=5 

在優先級相同的情況下,就出現了CPU資源的搶佔現象了 

從以上的運行結果可以知道main方法其實也是一個線程。在java中所有的線程都是同時啓動的,至於什麼時候,哪個先執行,完全看誰先得到CPU的資源。

java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。因爲每當使用java命令執行一個類的時候,實際上都會啓動一個JVM,每一個jVM實習在就是在操作系統中啓動了一個進程。

線程的中斷

實例: 

  1. public class SleepInterrupt implements Runnable { 
  2.     public void run() { 
  3.         System.out.println("1、進入run方法體線程正常啓動!!"); 
  4.         try { 
  5.             System.out.println("2、線程休眠3秒"); 
  6.             Thread.sleep(3000); 
  7.             System.out.println("3、線程正常休眠3秒"); 
  8.         } catch (InterruptedException e) { 
  9.             System.out.println("4、線程被中斷了!!!"); 
  10.         } 
  11.         System.out.println("5、正常結束run方法"); 
  12.         System.out.println(Thread.currentThread().getName() + "線程正在運行"); 
  13.     } 

TestSleepInterrupt類調用:

  1. public class TestSleepInterrupt { 
  2.     public static void main(String[] args) { 
  3.         SleepInterrupt sleepInterrupt = new SleepInterrupt(); 
  4.         Thread thread = new Thread(sleepInterrupt, "singsong"); 
  5.         thread.start(); 
  6.         try { 
  7.             Thread.sleep(3000); 
  8.         } catch (InterruptedException e) { 
  9.             e.printStackTrace(); 
  10.         } 
  11.         thread.interrupt(); 
  12.     } 

運行結果:

  1. 1、進入run方法體線程正常啓動!! 
  2. 2、線程休眠3秒 
  3. 3、線程正常休眠3秒 
  4. 5、正常結束run方法 
  5. singsong線程正在運行 

在啓動線程時,要若不加此句“Thread.sleep(3000);”程序進入執行中斷操作,

執行結果:

 

  1. 1、進入run方法體線程正常啓動!! 
  2. 2、線程休眠3秒 
  3. 4、線程被中斷了!!! 
  4. 5、正常結束run方法 
  5. singsong線程正在運行 

執行線程睡眠操作,拋出中斷異常,因此要有異常處理

public static void sleep(long millis, int nanos) throws InterruptedException

線程的強制執行jion()方法:

  1. public class JoinDemo implements Runnable { 
  2.     public void run() { 
  3.  
  4.         for (int i = 0; i < 10; i++) { 
  5.             System.out.println(Thread.currentThread().getName() + i); 
  6.         } 
  7.     } 
  8.  
  9.     public static void main(String[] args) { 
  10.         Thread thread = new Thread(new JoinDemo()); 
  11.         thread.setName("singsong"); 
  12.             thread.start(); 
  13.  
  14.         for (int i = 0; i < 10; i++) { 
  15.             if (i == 5) { 
  16.                 try { 
  17.                     thread.join(); 
  18.                 } catch (InterruptedException e) { 
  19.                     e.printStackTrace(); 
  20.                 } 
  21.             } 
  22.             System.out.println(Thread.currentThread().getName() + i); 
  23.         } 
  24.     } 

運行結果:

  1. main0 
  2. main1 
  3. main2 
  4. main3 
  5. main4 
  6. singsong0 
  7. singsong1 
  8. singsong2 
  9. singsong3 
  10. singsong4 
  11. singsong5 
  12. singsong6 
  13. singsong7 
  14. singsong8 
  15. singsong9 
  16. main5 
  17. main6 
  18. main7 
  19. main8 
  20. main9 

 

從運行結果中:本程序啓動了兩個線程:一個是main線程,另一個是singsong線程

當main線程中循環執行到第五次時,就強制執行singsong線程。Join()方法就是用來強制某一線程的運行。

後臺線程與setDaemon()方法

java 程序來說,只要還有一個前臺線程在運行,這個進程就不還結束,如果一個進程中只有後臺線程在運行,這個進程就會結束。前臺進程是相對後臺線程而言的。如果某個線程對象在啓動(調用start()方法)之前調用了setDaemon(true)方法,這個線程就變成了後臺線程。

實例:

  1. public class SetNameDemo implements Runnable { 
  2.     public void run() { 
  3.         while (true) { 
  4.             System.out 
  5.                     .println(Thread.currentThread().getName() + " is running"); 
  6.         } 
  7.     } 
  8.     public static void main(String[] args) { 
  9.             Thread thread = new Thread(new SetNameDemo()); 
  10.         thread.setName("singsong"); 
  11.         thread.setDaemon(true); 
  12.         thread.start(); 
  13.     } 

運行結果:

  1. singsong is running 
  2. singsong is running 
  3. singsong is running 
  4. singsong is running 
  5. singsong is running 

從運行結果可以看到:雖然創建了一個無限循環的線程,因爲它是後臺線程,因此整個進程在主線程結束時就隨之終止運行了。

同步與死鎖

多個線程共享同一個資源時需要進行同步,但是過多的同步會造成死鎖。

實例:

  1. public class Synchronized implements Runnable { 
  2.     private int ticket = 5
  3.     public void run() { 
  4.         for (int i = 0; i < 10; i++) { 
  5.             if (ticket > 0) { 
  6.                 try { 
  7.                     Thread.sleep(1000); 
  8.                 } catch (InterruptedException e) { 
  9.                     e.printStackTrace(); 
  10.                 } 
  11.                 System.out.println(Thread.currentThread().getName() + "在售出第" 
  12.                         + ticket-- + "票"); 
  13.             } 
  14.         } 
  15.     } 

SynchronizedTest調用:

  1. public class SynchronizedTest { 
  2.     public static void main(String[] args) { 
  3.         Synchronized syn=new Synchronized(); 
  4.         Thread thread =new Thread(syn ,"singsong"); 
  5.         Thread thread1=new Thread(syn,"singsong1"); 
  6.         thread.start(); 
  7.         thread1.start();     
  8.     } 

運行結果: 

  1. singsong1在售出第5票 
  2. singsong在售出第4票 
  3. singsong1在售出第3票 
  4. singsong在售出第2票 
  5. singsong1在售出第1票 
  6. singsong在售出第0票 

出現這個問題,是在程序中判斷剩餘票數與修改票數之間加入了睡眠語句(類似於網絡不好,有延遲時)。

如果想要解決這樣的問題,就必須使用同步,所謂的同步就是指多個操作在同一個時間段內只能有一個線程進行,其他線程要等待此線程完成之後纔可以繼續執行。

java中可以通過同步代碼的方式進行代碼的加鎖操作,通過加鎖可以保證同一個時間段內只能有一個線程進行。同步的實現有兩種方式。

同步代碼塊

語法格式:

synchronized(同步對象){//但是一般都把當前對象this作爲同步對象。

 //需要同步的代碼

}

同步方法:

語法格式:

synchronized 方法返回類型方法名(參數列表){

    // 其他代碼

}

實例:

同步代碼塊

  1. public void run() { 
  2.         for (int i = 0; i < 10; i++) { 
  3.             synchronized (this) {//同步代碼塊 
  4.                 if (ticket > 0) { 
  5.                     try { 
  6.                         Thread.sleep(1000); 
  7.                     } catch (InterruptedException e) { 
  8.                         e.printStackTrace(); 
  9.                     } 
  10.                     System.out.println(Thread.currentThread().getName() 
  11.                             + "在售出第" + ticket-- + "票"); 
  12.                 } 
  13.             } 
  14.         } 
  15.     } 
 

同步方法 

  1. public class Synchronized implements Runnable { 
  2.     private int ticket = 5
  3.     public void run() { 
  4.         for (int i = 0; i < 10; i++) { 
  5.             sale(); 
  6.         } 
  7.     } 
  8. //同步方法sale() 
  9.     public synchronized void sale() { 
  10.  
  11.         if (ticket > 0) { 
  12.             try { 
  13.                 Thread.sleep(1000); 
  14.             } catch (InterruptedException e) { 
  15.                 e.printStackTrace(); 
  16.             } 
  17.             System.out.println(Thread.currentThread().getName() + "在售出第" 
  18.                     + ticket-- + "票"); 
  19.         } 
  20.     } 

運行結果: 

  1. singsong在售出第5票 
  2. singsong在售出第4票 
  3. singsong在售出第3票 
  4. singsong在售出第2票 
  5. singsong1在售出第1票 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章