------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
如果一次只完成一個事情,還是比較容易實現的,但事實上很多事情都是同時執行的,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.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類中。
六、總結多線程本身也是比較復雜的問題,要完全理解它還需要時間,所謂孰能生巧,這些知識還是要多看多練多去實踐才能真正掌握。
新聞熱點
疑難解答