標籤:javase 多線程 java基礎
關於Java基礎的文章,我覺得寫得還可以,以前發在了我其它的部落格了,肯定是原創,現在再分享給大家出來。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
如果一次只完成一個事情,還是比較容易實現的,但事實上很多事情都是同時執行的,java為了類比這種狀態,引入了線程機制。
當程式同時完成多個事情時,就是所謂的多線程程式。
在一個時刻,單核的cpu只能運行一個程式。而我們看到的同時運行效果,只是cpu在多個進程間做著快速的隨機切換動作。
所以說多線程解決了多部分同時啟動並執行問題,但是線程太多的話肯定會影響效率。
首先老規矩一張圖來展現我們本次要介紹的內容:
一、實現方式
實現線程的方式一共有兩種---繼承Thread類和實現Runnable介面。
1、繼承Thread類。
a、定義類繼承Thread。
b、複寫Thread中的run方法。
c、建立定義類的執行個體對象。
d、調用start方法啟動線程。
class TestThread extends Thread // a、定義類繼承Thread。{ public void run() //b、複寫Thread中的run方法。 { for (int x = 0; x < 50 ;x++ ) { System.out.println(Thread.currentThread().getName()+"......"+x); } }}class Demo{ public static void main(String[] args) { TestThread t1= new TestThread();//c、建立定義類的執行個體對象。 TestThread t2= new TestThread(); t1.start(); //d、調用start方法啟動線程。 t2.start(); }}
2、實現runnable介面
a、定義類實現Runnable的介面。
b、覆蓋Runnable介面中的run方法。
c、通過Thread類建立線程對象。
d、調用start方法啟動線程。
class TestThread implements Runnable //a、定義類實現Runnable的介面。{public void run()// b、覆蓋Runnable介面中的run方法。{for (int x = 0; x < 50 ;x++ ){System.out.println(Thread.currentThread()+"++++++"+x);}}}class Demo{public static void main(String[] args) {TestThread d = new TestThread();Thread t1 = new Thread(d);Thread t2 = new Thread(d);//c、通過Thread類建立線程對象。t1.start(); //d、調用start方法啟動線程。t2.start();}}
3、實現Runnable介面的優勢
實際開發中,我們經常使用第二種方式做多線程,它的優勢在於
a、避免了按照物件導向的思想將任務封裝成對象。
b、避免了java單繼承的局限性。
二、線程的生命週期
線程具有生命週期,其各個生命週期的關係如。
三、安全執行緒
實際開發中,使用多線程的情況有很多,比如火車站售票系統,當有多個線程做取票動作時,假設此時只有一張票,一線程將票售出,此時二線程完成了判斷是否有票動作,並得出票數大於0結論。此時執行售票就會產生負數。
1、安全問題產生的原因
a、多個線程在操縱共用資料
b、操縱共用資料的代碼有多條。
2、解決辦法--同步
將多條操作共用資料的線程代碼封裝起來,當有線程執行這些代碼時候,其他線程不可參與。
a、同步代碼塊
synchronized(obj){ //需要同步的代碼}
b、同步函數
public synchronized void show() { //需要同步的代碼}
3、同步函數和同步代碼塊的區別
同步函數的鎖是this
同步代碼塊的鎖是任意的(也可以是this)
實際開發中建議用同步代碼塊。
4、同步的利弊
好處:解決了多線程的安全問題。
弊端:多個線程需要判斷鎖,較為消耗資源。
5、靜態函數代碼塊
如果同步函數被靜態修飾後,使用的鎖是什麼呢?設計模式中的單例模式給大家展示。
//懶漢式class Single{ private static Single s = null; private Single(){} public static Single getInstance() { if(s == null) { synchronized(Single.class) //靜態方法寫---類名.class { if(s==null) s = new Single(); } } return s; }}
四、線程間通訊
線程間的通訊其實就是多個線程共用同一個資源。
class ResorceDemo{ public static void main(String[] args) { Resorce r = new Resorce(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); }}class Resorce //定義一個資源{ String name; String sex; boolean flag = false;}class Input implements Runnable//寫入資源{ Resorce r; Input(Resorce r) { this.r = r; } public void run()//複寫run方法 { int x = 0;//x相當於一個標誌. while (true) { synchronized(r) { if (r.flag == true) { try { r.wait(); } catch (InterruptedException e) { } } else { if (x==0) { r.name = "mike"; r.sex = "nan"; } else { r.name = "傻妞"; r.sex = "妞妞妞妞i牛i牛ii牛"; } r.flag = true; r.notify();//喚醒 } x = (x+1)%2;//x在0和1之間相互交替. } } }}class Output implements Runnable//讀取資源{ Resorce r; Output(Resorce r) { this.r = r; } public void run() { while (true)//無限迴圈 { synchronized(r) { if (r.flag == false) { try { r.wait(); } catch (InterruptedException e) { } } else { System.out.println(r.name + "..."+r.sex); r.flag = false; r.notify(); } } } }}
五、常見操作方法
1,wait(): 讓線程處於凍結狀態,被wait的線程會被儲存到線程池中。
2,notify():喚醒線程池中一個線程(任意).
3,notifyAll():喚醒線程池中的所有線程。
4,setPriority():設定優先權
5,yield():暫停當前線程,讓其他線程執行。
當然,這些常見的操作方法在API中都可以查到,這不是我要說的重點,下面來對這些方法做一下比較。
(1)wait 和 sleep 區別?
1,wait可以指定時間也可以不指定。 sleep必須指定時間。
2,在同步中時,對cpu的執行權和鎖的處理不同。 wait:釋放執行權,釋放鎖。 sleep:釋放執行權,不釋放鎖。
(2)wait(),notify(),notifyAll(),用來操作線程為什麼定義在了Object類中?
a,這些方法存在與同步中。
b,使用這些方法時必須要標識所屬的同步的鎖。同一個鎖上wait的線程,只可以被同一個鎖上的notify喚醒。
c,鎖可以是任意對象,所以任意對象調用的方法一定定義Object類中。
六、總結
多線程本身也是比較複雜的問題,要完全理解它還需要時間,所謂孰能生巧,這些知識還是要多看多練多去實踐才能真正掌握。
java基礎3:多線程