線程淺談,淺談多線程和異步
一。線程的實現方式有兩種:
一種是繼承Thread類,重寫run()方法。這種方法有兩種不足:1.由於Java是單繼承的,所以當一個類繼承了Thread類雨 後就不能繼承其他的類了。
2.線程內部重寫了run()方法來定義任務導致了線程與任務 有一個強耦合關系,線程會變得重用性,靈活度非常低
第二種是:繼承Runable接口。
calss RunnableTest implements Runnable{}
RunnableTest r=new RunnableTest();
Thread t=new Thread(r);
t.start();
運用:(用匿名內部類來創建)
Thread t=new Thread(new Runnable(){
public void run(){ 實現代碼}
});
t.start();
結論:
start()方法是將線程納入到線程調度中來。當CPU給該線程分配下時間片段時,這時才自動調用run()方法來執行代碼。
面試題:
運行結果為pongping
結論:線程的啟動必須用start()方法,若調用run()方法來啟動。那麼這裡將不會啟動一個線程,相當於簡單調用了run方法
二。獲取線程相關信息的API:
1.獲取當前線程對象:Thread t=Thread.currentThread();
2.線程的id: long id=t.getId();
3.線程的名字:String name=t.getName();
4.線程的優先級: int priority=t.getPriority();
三。線程的優先級:
線程調度的工作不可控,對於線程而言:
1.分配的時間片長短不可控制
2.分配時間給哪個線程不可控。
線程只能被動的被分配時間片段,而不能主動地要求獲得時間片段。
而設置線程的優先級可以最大程度地干預線程調度工作,理論上,線程優先級高的線程分配的時間片段次數多。
設置: Thread t=new Thread(){ 重寫run()方法}; t.setPriority(Thread.MIN_PRIORITY);
四。static void sleep(long ms)方法
使運行當前方法的線程阻塞指定毫秒數。超時後,線程會再次回到runnable狀態,等待被分配時間片段。
Thread.sleep(5000);
該方法不用創建線程,可以在任何方法中使用。
Thread.yield();
//這個方法是讓出當前線程的時間片段。也是靜態方法
五。守護線程:(又名後台線程)
默認創建出來的線程都是前台線程。後台線程是要通過方法來指定,使前台線程變為後台線程。
後台線程和前台線程主要區別在:結束的時機。 當一個進程中的所有前台線程都結束時,進程結束,無論進程中的後台線程是否在運行都要強制結束。
用法:t.setDaemon(true);
注意:這個設置一定要在start()方法之前設置。
六。void join()方法
該方法會堵塞調用該方法的線程。
比如:a線程調用了b線程的join()方法,b.join()。那麼a線程就進入了阻塞狀態,知道b線程結束,a線程才會繼續執行,相當於b線程在a線程中插入。執行到插入那裡時,會執行b線程,b結束後,繼續執行a線程。
synchronized(同步鎖)
前提:(多個線程看到的必須是同一個對象)
1.多線程並發安全問題
由於線程切換的不確定和不可控,導致多個線程若操作同一資源的時候,可能出現嚴重問題,所以要向解決“各干各的”變為“排隊干”,這個時候就用到了synchonized(同步鎖)了。
2.方法用synchronized修飾
當一個方法被synchronized修飾後,該方法被稱作同步方法,不能被多個線程同時進入,上鎖的對象是當前方法的所屬對象。
3.用synchronized修飾代碼塊
有效的縮小同步范圍可以提高並發的效率。使用synchronized塊來縮小范圍。
因為所有上鎖的都是當前對象。所以這裡需要指定上鎖的對象,用synchronized(this){}來實現。給這段代碼上鎖。那麼多個線程不能同時進入到這段代碼中。
4.靜態方法上使用synchronized
當靜態方法上使用synchronized後,這裡上鎖的對象就是當前類的類對象。就是Class的對象。無論在哪調用這個方法都不能同時進入該靜態方法。(多個線程看到的是同一個對象)
5.互斥鎖
同一個對象中的兩個或多個不同的synchronized對象
6.死鎖
多個對象