在前面的作業系統的行程和執行緒中,對執行緒已經做了一些詳細的講解,對於java多線程實現,本文將再做一些介紹。
對於java中執行緒狀態,我們可以用五態模型來表示,分別為:
創建,就緒,運行,阻塞,終止五態
建立狀態:JVM呼叫main()方法會建立一個主線程,主線程透過呼叫線程物件的start()方法啟動一個子線程,新建的執行緒處於建立狀態,當執行緒運行的各種條件具備後,進入就緒佇列。
其他的各種狀態參考行程與執行緒中的講解。
java中建立一個執行緒有兩種方法,分別是透過繼承Thread類別和實作Runnable介面。具體介紹如下:
Java中可透過Thread類別及其子類別和Runnable介面實作多執行緒。
Thread類別可以直接定義線程對象,但一般需要定義Thread類別的子類別來實作多線程,以滿足程式設計的特殊要求。受到java單繼承的限制,在實際應用中,幾乎所有的多執行緒應用都採用實作runnable介面的方式實作多執行緒。
也就是說,如果新建的類別要繼承其他類,因為java中不支援多繼承,因此只能透過實作java.lang.Runnable 介面完成多執行緒任務,runnable適合多個相同程式碼的執行緒去處理相同資源的情況,把虛擬cpu(執行緒)同程式的程式碼、資料有效分開。
兩種執行緒的實作方式的程式碼如下:
public class ThreadDemo extends Thread { int i = 0; public void run(){ while (i<10){ System.out.println("实现Thread类继承的线程,正在占有处理机运行……"+i); try{ sleep(1000); i++; }catch (InterruptedException e){ e.printStackTrace(); } } } }
在main函數當中,我們只需實例化該類,呼叫start()方法便可以建立一個執行緒了。
public class RunnableDemo implements Runnable { int i = 0; @Override public void run(){ while (i<10) { System.out.println("实现Runnable接口的线程,正在占有处理机运行……" + i); try { Thread.sleep(1000); i++; } catch (InterruptedException e) { e.printStackTrace(); } } } }
main函數中實作方法:
Thread thread = new Thread(RunnableDemo ); Thread.start();
#執行緒的啟動:thread.start()
執行緒的結束:設定一個標記變量,以結束對應的循環及方法
暫時阻止線程的執行:Try{Thread.sleep(1000);}catch(InterruptedException e){ }
#設定線程優先權:setPriority(int priority)方法
Max_priority 執行緒可以具有的最高優先權(通常是10)
Min_priority 執行緒可以具有的最高優先權(通常是1)
Normal_priority 分配給線程的預設優先權(通常是5)
Java中有兩類線程:User Thread(用戶線程)和Daemon Thread(守護線程),Daemon線程的作用是為其他線程的運行提供服務,例如垃圾回收線程,在java程式中,若還有非Daemon線程,整個程式就不會結束。
透過setDaemon(true)方法設定守護線程
Jvm負責給線程分配cpu,稱為線程調度,原則:高優先權的執行緒先執行同等優先權的多個執行緒直接按時間片輪轉分配cpu資源
執行緒的不確定性:Java中一個簡單的語句對應到cpu中的多條指令,當一個線程剛剛執行了一個指令,被調度出後,後續線程重複調用原來的數據,導致線程的不確定性(不是原子性的)
線程同步:同時運行的線程需要共享數據,就必須考慮其它線程的狀態和行為,這時就需要實現同步Java引入了對象互斥鎖的概念,來保證共享數據操作的完整性。每個物件都對應一個monitor(監視器),它上面有一個稱為「互斥鎖(lock,mutex)」的標記,這個標記用來保證在任意時刻,只能有一個執行緒存取該物件。關鍵字synchronized用來與物件的互斥鎖聯繫
synchronized的用法:
對程式碼片段synchronized(物件){}
#對某個方法:synchronized放在方法宣告中,Public synchronized void push(char c){}相當於synchronized(this),表示整個方法為同步方法
執行緒同步控制:
使用wait()方法可以釋放物件鎖定
使用notify()或notifyAll()可以讓等待的一個或所有執行緒進入就緒狀態
Java裡面可以將wait和notify放在synchronized中,在synchronized執行期間,執行緒呼叫物件的wait方法,會釋放物件鎖定標識,然後進入等待狀態,然後其他執行緒呼叫notify()或notify()方法通知正在等待的執行緒。
具體程式碼如下:
class CubbyHole { private int index = 0; private int[] data = new int[3]; public synchronized void put(int value){ while (index == data.length){ try{ this.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } data[index++] = value; this.notify(); } public synchronized int get(){ while (index <=0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int value = data[index--]; this.notify(); return value; } }
在簡單的同步中,加鎖和解鎖很容易造成死鎖問題,也就是互相等待。 java在1.5以後引入了一些方法來解決多執行緒問題。
從JDK1.5以後提供了一系類別更好用的如單變數、集合、Timer、執行緒池。
原子變數java.util.concurrent.atomic套件AtomicInteger類別
GetAndIncrement()方法確保在執行緒存取時是安全的
並發的集合類別Java.util.concurrent套件中增加一些類別CopyOnWriteArrayList、CopyOnWriteSet
適合很少寫入而讀取頻繁的物件
ConcurrentHashMap
ArrayBlockingQueue生產者消費者使用put和get
使用線程池
線程池相關的類別ExecutorService介面、ThreadPoolExecutor類別Executors工具類別
常見的用法ExecutorService pool = Executors.newCachedThreadPool();
使用其execute(Runnable r)方法
以上是這絕對是最詳細的java多執行緒講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!