熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java多線程發展簡史

2022-06-13   來源: Java高級技術 

  

  引言

  首先問這樣一個問題如果提到Java多線程編程你會想到什麼?
   volatilesynchronized關鍵字?
   競爭和同步?
   鎖機制?
   線程安全問題?
   線程池和隊列?

  好吧請原諒我在這裡賣的關子其實這些都對但是又不足夠全面如果我們這樣來談論Java多線程會不會全面一些

  可是這未免太死板了不是麼?

  不如換一個思路我們少談一些很容易查到的語法不妨從歷史的角度看看Java在多線程編程方面是怎樣進化的這個過程中它做了哪些正確的決定犯了哪些錯誤未來又會有怎樣的發展趨勢?

  另外還有一點要說是我希望通過大量的實例代碼來說明這些事情Linus說Talk is cheap show me the code下文涉及到的代碼我已經上傳可以在此打包下載

  誕生

  Java的基因來自於月Sun公司的一個內部項目目標設備正是家用電器但是C++的可移植性和API的易用性都讓程序員反感旨在解決這樣的問題於是又了Java的前身Oak語言但是知道它正式更名為Java才算Java語言真正的誕生

  JDK

  月的JDK版本從一開始就確立了Java最基礎的線程模型並且這樣的線程模型再後續的修修補補中並未發生實質性的變更可以說是一個具有傳承性的良好設計

  搶占式和協作式是兩種常見的進程/線程調度方式操作系統非常適合使用搶占式方式來調度它的進程它給不同的進程分配時間片對於長期無響應的進程它有能力剝奪它的資源甚至將其強行停止(如果采用協作式的方式需要進程自覺主動地釋放資源也許就不知道需要等到什麼時候了)Java語言一開始就采用協作式的方式並且在後面發展的過程中逐步廢棄掉了粗暴的stop/resume/suspend這樣的方法它們是違背協作式的不良設計轉而采用wait/notify/sleep這樣的兩邊線程配合行動的方式

  一種線程間的通信方式是使用中斷

  public class InterruptCheck extends Thread {  
      
       @Override 
       public void run() {  
           Systemoutprintln(start);  
           while (true)  
               if (ThreadcurrentThread()isInterrupted())  
                   break;  
           Systemoutprintln(while exit);  
       }  
      
       public static void main(String[] args) {  
           Thread thread = new InterruptCheck();  
           threadstart();  
           try {  
               sleep();  
           } catch (InterruptedException e) {  
           }  
           threadinterrupt();  
       }  
   } 

  這是中斷的一種使用方式看起來就像是一個標志位線程A設置這個標志位線程B時不時地檢查這個標志位另外還有一種使用中斷通信的方式如下

  public class InterruptWait extends Thread {  
       public static Object lock = new Object();  
      
       @Override 
       public void run() {  
           Systemoutprintln(start);  
           synchronized (lock) {  
               try {  
                   lockwait();  
               } catch (InterruptedException e) {  
                   Systemoutprintln(ThreadcurrentThread()isInterrupted());  
                   ThreadcurrentThread()interrupt(); // set interrupt flag again  
                   Systemoutprintln(ThreadcurrentThread()isInterrupted());  
                   eprintStackTrace();  
               }  
           }  
       }  
      
       public static void main(String[] args) {  
           Thread thread = new InterruptWait();  
           threadstart();  
           try {  
               sleep();  
           } catch (InterruptedException e) {  
           }  
           threadinterrupt();  
       }  
   } 

  在這種方式下如果使用wait方法處於等待中的線程被另一個線程使用中斷喚醒於是拋出InterruptedException同時中斷標志清除這時候我們通常會在捕獲該異常的地方重新設置中斷以便後續的邏輯通過檢查中斷狀態來了解該線程是如何結束的

  在比較穩定的JDK 版本中已經可以找到Thread和ThreadUsage這樣的類這也是線程模型中最核心的兩個類整個版本只包含了這樣幾個包javaio javautiljavaawt和javaapplet所以說Java從一開始這個非常原始的版本就確立了一個持久的線程模型

  值得一提的是在這個版本中原子對象AtomicityXXX已經設計好了這裡給出一個例子說明i++這種操作時非原子的而使用原子對象可以保證++操作的原子性

  import ncurrentatomicAtomicInteger;  
      
   public class Atomicity {  
      
       private static volatile int nonAtomicCounter = ;  
       private static volatile AtomicInteger atomicCounter = new AtomicInteger();  
       private static int times = ;  
      
       public static void caculate() {  
           times++;  
           for (int i = ; i < ; i++) {  
               new Thread(new Runnable() {  
                   @Override 
                   public void run() {  
                       nonAtomicCounter++;  
                       atomicCounterincrementAndGet();  
                   }  
               })start();  
           }  
      
           try {  
               Threadsleep();  
           } catch (InterruptedException e) {  
           }  
       }  
      
       public static void main(String[] args) {  
           caculate();  
           while (nonAtomicCounter == ) {  
               nonAtomicCounter = ;  
               atomicCounterset();  
               caculate();  
           }  
      
           Systemoutprintln(Nonatomic counter:  + times + : 
                   + nonAtomicCounter);  
           Systemoutprintln(Atomic counter:  + times + : + atomicCounter);  
       }  
   } 

  上面這個例子你也許需要跑幾次才能看到效果使用非原子性的++操作結果經常小於

  對於鎖的使用網上可以找到各種說明但表述都不夠清晰請看下面的代碼

  public class Lock {  
       private static Object o = new Object();  
       static Lock lock = new Lock();  
      
       // lock on dynamic method  
       public synchronized void dynamicMethod() {  
           Systemoutprintln(dynamic method);  
           sleepSilently();  
       }  
      
       // lock on static method  
       public static synchronized void staticMethod() {  
           Systemoutprintln(static method);  
           sleepSilently();  
       }  
      
       // lock on this  
       public void thisBlock() {  
           synchronized (this) {  
               Systemoutprintln(this block);  
               sleepSilently();  
           }  
       }  
      
       // lock on an object  
       public void objectBlock() {  
           synchronized (o) {  
               Systemoutprintln(dynamic block);  
               sleepSilently();  
           }  
       }  
      
       // lock on the class  
       public static void classBlock() {  
           synchronized (Lockclass) {  
               Systemoutprintln(static block);  
               sleepSilently();  
           }  
       }  
      
       private static void sleepSilently(long millis) {  
           try {  
               Threadsleep(millis);  
           } catch (InterruptedException e) {  
               eprintStackTrace();  
           }  
       }  
      
       public static void main(String[] args) {  
      
           // object lock test  
           new Thread() {  
               @Override 
               public void run() {  
                   lockdynamicMethod();  
               }  
           }start();  
           new Thread() {  
               @Override 
               public void run() {  
                   lockthisBlock();  
               }  
           }start();  
           new Thread() {  
               @Override 
               public void run() {  
                   lockobjectBlock();  
               }  
           }start();  
      
           sleepSilently();  
           Systemoutprintln();  
      
           // class lock test  
           new Thread() {  
               @Override 
               public void run() {  
                   lockstaticMethod();  
               }  
           }start();  
           new Thread() {  
               @Override 
               public void run() {  
                   lockclassBlock();  
               }  
           }start();  
      
       }  
   } 

  上面的例子可以反映對一個鎖競爭的現象結合上面的例子理解下面這兩條就可以很容易理解synchronized關鍵字的使用


   非靜態方法使用synchronized修飾相當於synchronized(this)
   靜態方法使用synchronized修飾相當於synchronized(Lockclass)
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27270.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.