Java多線程
進程:系統進行資源分派和調度的一個獨立單位
線程:在進程中獨立啟動並執行子任務 使用多線程:多線程是非同步
線程啟動順序與start()執行順序無關
非安全執行緒:指多個線程對同一個對象中的同一個執行個體變數進行操作時會出現值被更改、值不同步的情況,進而影響程式的執行流程。
解決方案:在run方法前加入synchronized關鍵字,使多個線程在執行run方法時,以排隊的方式進行處理
public class MyThread extends Thread{ private int count = 5; @Override synchronized public void run(){ super.run(); count--; System.out.println("由"+this.currentThread().getName()+" 計算,count="+count); }}
停止線程
在Java中有三種方法可以終止正在啟動並執行線程: 使用退出標誌,使線程正常退出,也就是當run方法完成後線程終止 使用stop方法強行終止線程(不推薦),因為stop和suspend及resume一樣,都是作為到期的方法,使用它們可能產生不可預料的結果 使用interrupt方法中斷線程
判斷線程是否是停止狀態,Thread類中有以下兩個方法: this.interrupted():測試當前線程是否已經中斷,執行後具有將狀態標誌置為清除狀態(false)的功能 this.isInterrupted():測試線程是否已經中斷,不清除狀態標誌 暫停線程
suspend()方法暫停線程,resume()方法恢複線程的執行
缺點: 獨佔,使用suspend和resume方法時,如果使用不當,極易造成公用的同步對象的獨佔,使得其他線程無法訪問公用同步對象 不同步,容易出現因為線程的暫停而導致資料不同步的情況 yield方法
yield()方法的作用是放棄當前的CPU資源,將它讓給其他的任務去佔用CPU執行時間,但放棄的時間不確定,有可能剛剛放棄,馬上又擷取CPU時間片 線程的優先順序 CPU優先執行優先順序較高的線程對象中的任務,設定線程優先順序使用setPriority()方法,值為1~10 線程優先順序具有繼承性,比如A線程啟動B線程,則B線程的優先順序與A線程是一樣的 優先順序具有一定的規則性,也就是CPU盡量將執行資源讓給優先順序比較高的線程 優先順序具有隨機性 守護線程
在Java線程中有兩種線程,一種是使用者線程,另一種是守護線程
守護線程是一種特殊的線程,它的特性有”陪伴”的含義,當進程中不存在非守護線程了,則守護線程自動銷毀。典型的守護線程就是記憶體回收線程 對象及變數的並發訪問 synchronized同步方法 方法內的變數為安全執行緒(方法內變數為私人變數) 多個對象多個鎖 可重新進入鎖,自己可以再次擷取自己的內部鎖 出現異常,鎖自動釋放 同步不具有繼承性 synchronized同步語句塊
用關鍵字synchronized聲明方法在某些情況下是有弊端的,比如A線程調用同步方法執行一個長時間的任務,那麼B線程必須等待比較長的時間
synchronized同步代碼塊的使用:當兩個並發線程訪問同一個對象object中的synchronized(this)同步代碼塊時,一段時間內只能有一個線程被執行,另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。
即為在synchronized塊中就是同步執行,不在synchronized塊中就是非同步執行,這樣可以提高運行效率
在使用synchronized(this)代碼塊時需要注意的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對同一個object中所有其他synchronized(this)同步代碼塊的訪問將被阻塞,這說明synchronized使用的”對象監視器”是一個
同步synchronized(this)代碼塊是鎖定當前對象的
除了使用synchronized(this)格式來同步代碼塊外,Java還支援對”任意對象”作為”對象監視器”來實現同步功能,這個”任意對象”大多數是執行個體變數及方法的參數,使用格式為synchronized(非this對象x) 1)在多個線程持有”對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼——當多個線程同時執行synchronized(x){}同步代碼塊時呈同步效果 2)當持有”對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼——當其他線程執行x對象中synchronized同步方法時呈同步效果 3)鎖非this對象具有一定的優點:如果在一個類中有很多個synchronized方法,這時雖然能實現同步,但會受到阻塞,所以影響運行效率,但如果使用同步代碼塊鎖非this對象,則synchronized(非this)代碼塊中的程式與同步方法是非同步,不與其他鎖this同步方法爭搶this鎖,則可以大大提高運行效率——當其他線程執行x對象方法裡面的synchronized(this)代碼塊時也呈現同步效果 靜態同步synchronized方法與synchronized(class)代碼塊
關鍵字synchronized還可以應用在static靜態方法上,相當於對當前*.java檔案對應的Class類進行持鎖,Class鎖可以對類的所有對象執行個體起作用
同步synchronized(class)代碼塊的作用和synchronized static方法的作用一樣 多線程的死結
死結:不同的線程都在等待根本不可能被釋放的鎖,從而導致所有的任務都無法繼續完成
當多個線程同時持有鎖對象時,如果持有的是相同的鎖對象,這些線程之間就是同步的,否則就是非同步 volatile關鍵字
主要作用是使變數在多個線程間可見,關鍵字volatile強制從公用堆棧中取得變數的值,而不是從線程私人資料棧中取得變數的值
public class RunThread extends Thread { volatile private boolean isRunning = true; public boolean isRunning(){ return isRunning; } public void setRunning(boolean isRunning){ this.isRunning = isRunning; } @Override public void run(){ System.out.println("進入run了"); while(isRunning == true){ } System.out.println("線程被停止了。"); } } public class Run { public static void main(String[] args){ try{ RunThread thread = new RunThread(); thread.start(); Thread.sleep(1000); thread.setRunning(false); System.out.println("已經賦值為false"); }catch(InterruptedException e){ e.printStackTrace(); } } }
volatile具有非原子的特性,可能導致線程不安全,可以用synchronized關鍵字實現同步或使用AtomicInteger原子類進行實現
private AtomicInteger count = new AtomicInteger(0); ... count.incrementAndGet();//自增1
synchronized代碼塊有volatile同步的功能
關鍵字synchronized可以使多個線程訪問同一個資源具有同步性,而且它還具有將線程工作記憶體中的私人變數與公用記憶體中的變數同步的功能