多線程(一)

來源:互聯網
上載者:User

標籤:提高   時間段   alt   路徑   nal   call   java虛擬機器   重寫   好處   

1 進程
  • 進程:
    • 正在運行中的程式,是系統進行資源分派和調用的獨立單位。
    • 每一個進程專屬它自己的記憶體空間和系統資源。

 

  • 多進程的意義:
    • 單進程電腦只能做一件事情,而我們現在的電腦都可以一邊玩遊戲,一邊聽音樂,所以我們常見的作業系統都是多進程作業系統。比如Linux和Mac等,能在同一段時間內執行多個任務。
    • 對於單核電腦而言,遊戲進程和聽音樂進程是同時啟動並執行,當然不是,因為CPU在某個時間點上只能做一件事情,電腦是在遊戲進程和聽音樂進程間做頻繁切換,且切換速度很快,所以,我們感覺遊戲和音樂是同時進行的,其實並不是同時進行的。
    • 多進程的作用不是提高執行速度,而是為了提高CPU的使用效率。  

 

2 線程
  • 線程是進程中的單個順序控制流程,是一條執行路徑。或者換句話說,一個進程內部可以執行多個任務,而每一個任務我們都可以看成是一個線程。
  • 一個進程如果只有一條執行路徑,就稱為單線程程式。
  • 一個進程如果有多條執行路徑,就稱為多線程程式。

 

3 多線程存在的意義
  • 多線程的作用不是為了提高CPU的使用效率,而是為了提高應用程式的使用效率。
  • 多線程給我們的錯覺就是讓我們認為多個線程是並發執行的,其實不然,因為多個線程是共用一個進程的資源(堆記憶體和方法區),但是棧記憶體是獨立的,一個線程一個棧,所以他們仍然是在搶CPU的資源執行。一個時間點上只有一個線程執行,而且誰搶到,不一定,所以,造成了線程啟動並執行隨機性。

 

  • 並發:是一個時間段同時運行多個程式。
  • 並行:是一個時間點上同時運行多個程式。

 

4 java程式的運行原理
  • java命令會啟動java虛擬機器,啟動JVM,等於啟動了一個應用程式,也就是啟動了一個進程。該進程會自動啟動一個“主線程”,然後主線程去調用某個類的main方法,所以main方法運行在主線程中。但是JVM啟動還會啟動記憶體回收線程,所以java程式是多線程的。

 

  • 驗證:記憶體回收線程
package java012;/** * 2017/9/29 * 說明: */class Demo {    public void finalize(){        System.out.println("我要死了");    }}public class ThreadDemo {    public static void main(String[] args) {        new Demo();        new Demo();        System.gc();        new Demo();        System.out.println("你好世界");    }}

 

5 多線程的好處和弊端
  • 好處:“適當”提高程式的執行效率、“適當”提高CPU和記憶體的利用率、線程執行完成後會自動銷毀節省記憶體。
  • 弊端:每開啟一條線程就會佔用一定記憶體空間,降低程式效能;線程越多,CPU調度(多個線程之間切換)開銷越大,時間開銷、空間開銷。

 

 

6  線程的建立方式一-
  •  建立線程的步驟:
    • ①定義一個類繼承Thread類
    • ②覆蓋Thread類中的run方法
    • ③建立Thread類的子類對象  
    • ④調用start()方法,啟動線程並調用自訂線程的run()方法

 

  •  解釋為什麼建立線程需要繼承Thread,並重寫run方法。
    • 建立線程的目的是為了開啟一條執行路徑,去運行指定的代碼和其他代碼並發運行。而運行指定的代碼就是這個執行路徑的任務。JVM建立的主線程的任務都是定義在main方法中, 那麼自訂的線程的任務在哪裡你?Thread類用於描述線程,線程需要任務的,所以Thread提供了對任務的描述,這個任務就是Thread類的run方法來體現的,也就是說,run方法就是封裝自訂線程運行任務的函數。那麼此時你可能會想,我們直接new Thread().run()方法不就可以了,那麼非常抱歉,此時,啟動並執行不是我需要並發執行的代碼,而是Thread類中的run()方法中的代碼,可惜的是,不是我要的,所以,這就是為什麼在java中,我們建立線程需要繼承Thread類,並重寫run()方法的原因。 

 

  •  樣本:建立線程
package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<100;x++){            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(name+":"+x);        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.start();        d2.start();    }}

 

 6.1 線程的一些方法
  •  返回該線程的名稱
public final String getName()
package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<10;x++){            System.out.println(name+":"+x+":線程的名稱:"+getName());        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.run();        d2.run();    }}

結果好像不對,因為我們並沒有調用start()方法,那麼此時啟動並執行列印的線程的名稱應該是main之類的。對,應該列印的是main之類的,但是,我們要知道,我們調用的是Thread的無參構造方法。代碼如下所示: 

package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        super();//調用父類的無參構造方法        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<10;x++){            System.out.println(name+":"+x+":線程的名稱:"+getName());        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.run();        d2.run();    }}

那麼,此時我們觀察Thread的源碼就可以知道答案:

/**     * Allocates a new {@code Thread} object. This constructor has the same     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}     * {@code (null, null, gname)}, where {@code gname} is a newly generated     * name. Automatically generated names are of the form     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.     */    public Thread() {        init(null, null, "Thread-" + nextThreadNum(), 0);    }

這下知道原因了吧。

  • 返回對當前正在執行的線程的引用。
public static Thread currentThread()
package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        super();//調用父類的無參構造方法        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<10;x++){            System.out.println(name+":"+x+":線程的名稱:"+Thread.currentThread().getName());        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.run();        d2.run();    }}

上面的代碼證明了2點:①如果我們不調用自訂線程的start()方法,就不是開啟新的線程②想擷取運行時的線程,必須通過Thread.currentThread()。

package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        super();//調用父類的無參構造方法        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<10;x++){            System.out.println(name+":"+x+":線程的名稱:"+Thread.currentThread().getName());        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.start();        d2.start();        System.out.println("主線程的名字:"+Thread.currentThread().getName());    }}

  • 給線程取有意義的名稱,而不是預設的。
public Thread(String name)
package java012;/** * 2017/9/29 * 說明: */class Demo extends Thread {    private String name;    public Demo(String name){        super(name);//調用父類的有參構造方法,給線程取定義的名稱        this.name = name;    }    public void run(){        this.show();    }    public void show(){        for(int x =0;x<10;x++){            System.out.println(name+":"+x+":線程的名稱:"+Thread.currentThread().getName());        }    }}public class ThreadDemo {    public static void main(String[] args) {        Demo d1 = new Demo("d1");        Demo d2 = new Demo("d2");        d1.start();        d2.start();        System.out.println("主線程的名字:"+Thread.currentThread().getName());    }}

 

多線程(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.