Java從菜鳥到精通(9)

來源:互聯網
上載者:User

多線程(Thread)
*進程
*線程(例:FlashGet,迅雷)
*多線程存在的意義
*線程的建立方式
*多線程的特性

進程:是一個正在執行中的程式。
    每一個進程執行都有一個執行的順序,該

順序就是一個執行路徑(情景),或者叫一個控制

單元。

線程:就是進程中的一個獨立的控制單元,線程在

控制著進程的執行。

一個進程中至少有一個線程。

java JVM 啟動的時候會有一個進程即Java.exe
該進程中至少有一個線程來負責java程式的執行
而且這個線程啟動並執行代碼存在於main方法中。
該線程稱之為主線程。

擴充:其實更細節說明JVM,JVM啟動不止一個線程

,還有負責記憶體回收機制的線程。

1.如何在自訂的代碼中,自訂一個線程呢?
通過對API的尋找,java已經提供了對線程這類 事

物的描述,就是Thread類。
建立線程的第一種方式:繼承Thread類
步驟:
1、定義類繼承Thread;
2、複寫Thread類中的run方法
    目的:將自訂的代碼儲存在run方法中

,讓線程運行。
3、調用線程的start 方法,該方法有兩個作用:

一、啟動線程;二、調用run方法

例:
class Demo extends Thread
{
   //覆蓋Run方法
    public void run(){
    syso("demo run");
    }

}
class ThreadDemo{

    public static void main(String[]

args){
        Demo d=new Demo();//建立好一

個線程
        //d.start();
        d.run();
********面試******    
    RUN():僅僅是對象調用方法。而線程創

建了,並沒有運行。
    Start():開啟線程並執行該線程的run方

法。
    }
}

發現運行結果每一次都不同。
因為多個程式都在擷取CPU的執行權。CPU執行到誰

,誰就執行。
明確一點,在某一時刻,只能有一個程式在運行。

(多核CPU除外)
CPU在做著快速的切換,以達到看上去是同時運行

的效果。
我們可以形象把多線程的運行行為在互相搶奪CPU

的執行權。

這就是多線程的一個特性:隨機性。

為什麼要覆蓋Run方法呢?
Thread類用於描述線程。
該類就定義了一個功能,用於儲存線程要啟動並執行代

碼,該儲存功能就是run方法。

也就是說Thread類中的run方法,用於儲存線程要

啟動並執行代碼。

例子:
建立兩個線程,和主線程交替運行。

class Test extends Thread
{
  public void run(){
    for(int i=0;i<60;i++){
        syso("test run"+x);
    }
    }
}
class ThreadTest{

    public static void main(String []

args){
    Test t1=new Test();
    Test t2=new Test();
    t1.start();    
    t2.start();

    for(int j=0;j<60;j++){
        syso("main...."+x);
    }

    }
}

建立線程方式一
繼承thread類
1、子類覆蓋父類中的run方法,將線程啟動並執行代碼

存放在RUN中。
2、建立子類對象的同時線程也被建立。
3、通過調用start方法開啟線程。

線程的第一種狀態:被建立,繼承Thread
線程的第二種狀態:凍結,時間到了就能運行

(sleep(time))
線程的第三種狀態:凍結,但是自己不能運行,(

wait等待自己不能返回(),notify喚醒());放棄

了執行資格。先從凍結上回到臨時狀態上,然後執

行。
線程的第四種狀態:消亡,stop(),run方法結束


線程的特殊狀態(臨時(阻塞)狀態):具備運行

資格,沒有執行權。

線程都有自己預設的名稱。
getName()方法//擷取線程名稱。設定線程名稱:

setName或者構造方法。
Thread.currentThread()方法  //擷取,當前線程

對象。時靜態。通用方式。

/*
需求:簡單的賣票程式。
多個視窗同時賣票。
*/
class Ticket extends Thread
{    
    //用靜態,一般不定義靜態,生命週期

太長
    private static int tick=100;
    public void run(){
      while(true){

    if(tick>0){
    syso(Thread.currentThread

().getName+".....sale:"+tick--);
        }
    }
    }
}

class TicketDemo
{
    public static void main(String[]

args){
    

//***************第1。種
    Ticket t1=new Ticket();    
    //Ticket t2=new Ticket();    
    //Ticket t3=new Ticket();    
    //Ticket t4=new Ticket();    
    //這樣會運行異常:無效的線程啟動異常
    t1.start();
    t1.start();
    t1.start();
    t1.start();
//************該如何解決呢?第二種建立方式
    }

}

建立線程的第二種方法是:聲明實現Runnable介面

的類,該類然後實現run方法。然後可以分配該類

的執行個體,在建立Thread時作為一個參數來傳遞並啟

動。採用這種風格的同一個例子如下(JDK):
class PrimeRun implements Runnable{
    long minPrime;
    PrimeRun(long minPrime){
    this.minPrime=minPrime;
    }
    
    public void run(){
    
    }
}

建立線程的第二種方式:實現Runnable介面
步驟:
1.定義類實現Runnable介面
2.覆蓋Runnable介面中的run方法
    將線程要啟動並執行代碼存放在該Run方法中
3.通過Thread類建立線程對象
4.將Runnable介面的子類對象作為實際參數傳遞給

Thread類的建構函式。
    為什麼要將Runnable介面的子類對象傳遞

給Thread的建構函式。
    因為,自訂的run方法所屬的對象是

Runnable介面的子類對象。所以要讓線程去指定指

定對象的run方法。就必須明確該run方法所屬的對

象。

5.調用Thread類的start方法開啟線程並調用

Runnable介面子類的run方法。

******面試****
實現方式和繼承方式有什麼區別?
實現方式好處:避免了單繼承的局限性。
    在定義線程時,建議使用實現方式。
兩種方式區別:
繼承Thread:線程代碼存放在Thread子類run方法

中。
實現Runnable:線程代碼存在介面的字了的run方

法中。

-------------------------------------
售票簡單程式的另一種:
通過分析,發現,列印除了0,-1,-2等錯票

多線程的運行出現了安全問題。

問題的原因:
    當多條語句在操作同一個線程共用資料時

,一個線程對多條語句只執行了一部分,還沒有執

行完另一個線程參與進來執行,導致共用資料的錯

誤。

解決辦法:
    對多條操作共用資料的語句,只能讓一個

線程都執行完,在執行過程中,其他線程不可以參

與執行。

Java對於多線程的安全問題提供了專業的解決問題

。就是同步代碼塊如下:

synchronized(對象){
    需要被同步的代碼
}
對象如同鎖。持有鎖的線程可以在同步中執行。沒

有持有鎖的線程即使擷取了CPU的執行權,也進不

去,因為沒有擷取鎖。

同步的前提:
1.必須要有兩個或者兩個以上的線程。
2.必須是多個線程使用同一個鎖。

*******************
必須保證同步中只能有一個線程在運行。
好處:解決了多線程的安全問題。
弊端:多個線程都需要判斷鎖,較為消耗資源。
一個是同步代碼塊;
一個是同步函數
******同步函數用的是哪個鎖?
函數需要被對象調用。那麼函數都有一個所屬對象

引用嗎,就是this。所以同步函數使用的鎖是this

如果同步函數被靜態函數修飾後,使用的鎖是什麼

呢?
不是this,因為靜態方法中的也不可以定義this。
靜態進記憶體時,記憶體中沒有本類對象,但是一定有

該類對應的位元組碼檔案對象。
類名.class 該對象的類型是Class。

靜態同步方法,使用的鎖是該方法所在類的位元組

碼檔案對象。也 就是:類名.class(唯一的)

class Ticket implements Runnable
{    
    
    private static int tick=100;

    //Object對象
    Object obj=new Object();

    public void run(){
      while(true){
//同步代碼塊(鎖旗標)
synchronized(obj){
    if(tick>0){
    syso(Thread.currentThread

().getName+".....sale:"+tick--);
        }
    }
    }
}
}

class TicketDemo
{
    public static void main(String[]

args){
    
    //這個建立的不是線程
    Ticket t=new Ticket();
    

    Ticket t1=new Ticket(t);    
    Ticket t2=new Ticket(t);    
    Ticket t3=new Ticket(t);    
    Ticket t4=new Ticket(t);
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.