進程和線程是動態的概念。 html
進程是 「執行中的程序「,是一個動詞,而程序是一個名詞,進程運行中程序的」代碼「,並且還有本身的計數器,寄存器,它會向系統申請系統資源。 java
線程是進程中的一個控制流。一個程序可能可能包含多個任務併發運行,而線程就是指一個任務重頭到尾的執行流。 多線程
說的在簡單點,線程是執行中的任務,一個程序包含多個任務。 併發
單處理器中,爲提升處理器的使用率(最終目標),使得程序在進行IO輸入出等不須要處理器時,也可以讓處理器在運轉,引進多線程處理機制。多線程可使得程序運行的更快,執行效率更高,交互性更強,這是不言而喻的! ide
一個任務是一個對象,因此爲建立一個任務,必須定義一個類,定義一個任務類,爲了說明這是一個任務類,它須要實現Runnable接口,這個接口只包含一個run方法。 學習
當咱們定義好任務類taskClass以後,就能夠用它的構造方法建立一個任務啦:TaskClass task = new TaskClass(.....); this
咱們建立的任務只能在線程中運行,Thread類中包含了建立線程以及控制線程的衆多方法。使用下面的語句建立任務線程:Thread thread = new Thread(task); 線程
而後調用start()方法告訴java虛擬機該線程準備運行:thread.start();以後java虛擬機經過調用任務的run()方法執行任務。 設計
事例代碼:htm
public class TaskThreadDemo{ public static void main(String[] args) { //建立任務 而且須要爲任務 建立 任務類,使用該類的構造方法建立任務 PrintChar printA = new PrintChar('a',100); PrintChar printB = new PrintChar('b',100); PrintNum print100 = new PrintNum(100); //爲任務建立線程 Thread thread1 = new Thread(printA); Thread thread2 = new Thread(printB); Thread thread3= new Thread(print100); //告訴虛擬機器線程開始運行 thread1.start(); thread2.start(); thread3.start(); } } class PrintChar implements Runnable { private char charToPrint; private int items; public PrintChar(char c,int t) { charToPrint = c; items = t; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<items;i++) { System.out.print(charToPrint); } } } class PrintNum implements Runnable { private int lastNumb; public PrintNum(int n) { lastNumb = n; } @Override public void run() { // TODO Auto-generated method stub for(int i= 1;i<100;i++) { System.out.print(" "+lastNumb); } }
}
一個好玩的閃爍文本框,直接用線程,不用main方法
import javax.swing.JApplet; import javax.swing.JLabel; public class FlashingText extends JApplet implements Runnable { private static final long serialVersionUID = 1L; private JLabel jlbText = new JLabel("Welcome",JLabel.CENTER); public FlashingText() { add(jlbText); new Thread(this).start(); } public void run() { try { while(true) { if(jlbText.getText()==null) jlbText.setText("Welcome"); else jlbText.setText(null); Thread.sleep(200); } } catch (Exception e) { // TODO: handle exception } } }
Thread類實現了Runnable接口,它包含爲任務而建立線程的構造方法,以及控制方法,下圖就是Thread類常見的控制線程的方法:
由於Thread類實現了Runnable接口,因此能夠定義一個Thread的擴展類,裏面實現run方法,這樣也能夠建立一個線程類,但並非很推薦這種方法,由於它將建立任務和運行任務的機制混在了一塊兒,將任務從線程中分離出來比較好,即儘可能使用Runnable接口建立線程,這樣獲得的線程更加靈活,避免了java單繼承帶來的侷限性。
線程池是管理併發執行任個數的理想方法,java提供Executor接口來執行線程池中的任務,提供ExecutorService接口來管理和控制任務。爲了建立Executor接口實例,咱們能夠用Executors類,Executors類提供了建立Executor接口對象的靜態方法,下圖描述了上面的上面所說的關係。
線程池中的shutdown()方法通常都是放在main方法的後面部分,當因此的線程都添加到線程池中,即使有線程沒有執行完畢,也可能會關閉線程池,未執行完的線程繼續執行,因此main方法可能比子線程先結束。
假若但願主線程在子線程所有作完以後在執行,能夠考慮讓因此的子線程用jion方法,但這可能致使全部子線程變成串行,不是很好的辦法,固然咱們也能夠多線程的輔助類CountDownLatch,這是一個與計時器有點相似功能的類。此次在看書學習的時候,發現了一個更好的辦法,就是在shutdown()方法後加上一句while(!executor.isTerminated()){},這是一個不錯的方法(不過我把shoudown()方法放在該while語句後面,就會陷入死循環,應該是要先關閉線程池,在判斷線程池中的線程是否所有終止,由於也有可能在while語句後面在添加新的子線程)。
isTerminated()方法:若是線程池中因此線程都已完成並終止,則返回true.
可使用CountDownLatch 和上面的方法對程序運行計時統計,不過我記得CountDownLatch類是須要指定線程的個數。
事例代碼
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorDemo { public static void main(String[] args){ long start = System.currentTimeMillis(); System.out.println("當前時間"+" "+start); ExecutorService executor = Executors.newFixedThreadPool(4); executor.execute(new PrintChar('a',100)); executor.execute(new PrintChar('b',100)); executor.execute(new PrintChar('c',100)); executor.execute(new PrintNum(100)); executor.shutdown(); while(!executor.isTerminated()){ //System.out.print("-"); }; long end = System.currentTimeMillis(); System.out.println("\n當前時間"+" "+end); System.out.println("\n用時"+" "+(end-start)+"毫秒"); } }
運行截圖
不過不知道運行太快的緣由,仍是啥別的緣由, 會出現截圖2的狀況,網上不多關於isTerminated()方法的介紹,若有大神知道緣由,還請告知小弟。
這篇博客是本身在學習《java語言程序設計進階篇》時所在筆記,代碼出自書上,最後那個記時的加了計時部分。大三開學在即,但願如今來學java還來得及。
本文出自於博客園蘭幽,轉載請說明出處。