Java基礎之多線程框架

一.進程與線程的區別html

1.定義:java

    進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。緩存

    線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程本身基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),可是它可與同屬一個進程的其餘的線程共享進程所擁有的所有資源。多線程

2.關係:併發

    一個線程能夠建立和撤銷另外一個線程;同一個進程中的多個線程之間能夠併發執行。app

相對進程而言,線程是一個更加接近於執行體的概念,它能夠與同進程中的其餘線程共享數據,但擁有本身的棧空間,擁有獨立的執行序列。框架

3.區別:優化

   進程和線程的主要差異在於它們是不一樣的操做系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。this

     3.1線程的劃分尺度小於進程,使得多線程程序的併發性高。spa

     3.2簡而言之,一個程序至少有一個進程,一個進程至少有一個線程

     3.3另外,進程在執行過程當中擁有獨立的內存單元,而多個線程共享內存,從而極大地提升了程序的運行效率。

    3.4線程在執行過程當中與進程仍是有區別的。每一個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。可是線程不可以獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。

   3.5從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分能夠同時執行。但操做系統並無將多個線程看作多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。

4.優缺點:

      線程和進程在使用上各有優缺點:線程執行開銷小,但不利於資源的管理和保護;而進程正相反。同時,線程適合於在SMP機器上運行,而進程則能夠跨機器遷移。

二.多線程兩個基本實現框架

       Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內部,程序的多任務是經過線程來實現的。每用Java命令啓動一個Java應用程序,就會啓動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它本身。在這個JVM環境中,全部程序代碼的運行都是以線程來運行。

      在Java中,多線程的實現有兩種基本方式:繼承java.lang.Thread類;實現java.lang.Runnable接口。(優先選擇)。

     第三種方式(少):使用ExecutorService、Callable、Future實現有返回結果的多線程。

1.繼承Thread類來實現多線程

當一個類繼承Thread類時,在類中必須重載run()方法,同時這個run()方法也是線程的入口,在調用的過程當中,經過調用start()方法來啓動新線程,其基本框架爲:

class 類名 extends Thread{
方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }

通常生活場窗口售票狀況:

 1 class TestThread extends Thread
 2  {
 3     private String name;
 4     public TestThread(String name)
 5      {
 6         this.name=name;
 7     }
 8      public void run()
 9     {
10 
11          for (int i = 0; i < 7; i++)
12         {
13             if (num > 0)
14             {
15                 System.out.println(name+"正在賣票  "+"num= " + num--);
16              }
17         }
18      }
19   
20     public static void main(String[] args)
21     {
22  
23         TestThread h1 = new TestThread("窗口1");
24         TestThread h2 = new TestThread("窗口2");
25         TestThread h3 = new TestThread("窗口3");
26        h1.start();
27        h2.start();
28        h3.start();
29      }
30     private int num = 4;
31  }

 

這樣出現的問題是:1.不清楚線程之間執行的具體順序,2.至關於每一個窗口都在售賣4張票。

優化方案:實現Runnable接口

2.實現Runnable接口來實現多線程

      和繼承Thread相似,當一個類實現Runnable接口時,在類中也必須重載run()方法,同時這個run()方法也是線程的入口,在調用的過程當中,經過調用start()方法來啓動新線程,其基本框架爲:

class 類名 implements Runnable{
 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }

代碼改進:

class MyThread implements Runnable
{ 
    private int ticket = 5;  //5張票
 
    public void run() 
    {
         for (int i=0; i<=20; i++) 
         {
            if (this.ticket > 0) 
             {
                 System.out.println(Thread.currentThread().getName()+ "正在賣票"+this.ticket--);
            }
         }
     }
 }
 public class TestThread {     
     public static void main(String [] args) 
     {
        MyThread my = new MyThread();
        new Thread(my, "1號窗口").start();
        new Thread(my, "2號窗口").start();
        new Thread(my, "3號窗口").start();
     }
 }

 

    程序執行的結果爲:

1 1號窗口正在賣票5
2 1號窗口正在賣票4
3 1號窗口正在賣票3
4 2號窗口正在賣票2
5 1號窗口正在賣票1

3.使用ExecutorService、Callable、Future實現有返回結果的多線程

     ExecutorService、Callable、Future這個對象實際上都是屬於Executor框架中的功能類。返回結果的線程是在JDK1.5中引入的新特徵,確實很實用,有了這種特徵我就不須要再爲了獲得返回值而大費周折了,並且即使實現了也可能漏洞百出。可返回值的任務必須實現Callable接口,相似的,無返回值的任務必須Runnable接口。

 1 import java.util.concurrent.*;  
 2 import java.util.Date;  
 3 import java.util.List;  
 4 import java.util.ArrayList;  
 5   
 6 /** 
 7 * 有返回值的線程 
 8 */  
 9 @SuppressWarnings("unchecked")  
10 public class Test {  
11 public static void main(String[] args) throws ExecutionException,  
12     InterruptedException {  
13    System.out.println("----程序開始運行----");  
14    Date date1 = new Date();  
15   
16    int taskSize = 5;  
17    // 建立一個線程池  
18    ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
19    // 建立多個有返回值的任務  
20    List<Future> list = new ArrayList<Future>();  
21    for (int i = 0; i < taskSize; i++) {  
22     Callable c = new MyCallable(i + " ");  
23     // 執行任務並獲取Future對象  
24     Future f = pool.submit(c);  
25     // System.out.println(">>>" + f.get().toString());  
26     list.add(f);  
27    }  
28    // 關閉線程池  
29    pool.shutdown();  
30   
31    // 獲取全部併發任務的運行結果  
32    for (Future f : list) {  
33     // 從Future對象上獲取任務的返回值,並輸出到控制檯  
34     System.out.println(">>>" + f.get().toString());  
35    }  
36   
37    Date date2 = new Date();  
38    System.out.println("----程序結束運行----,程序運行時間【"  
39      + (date2.getTime() - date1.getTime()) + "毫秒】");  
40 }  
41 }  
42   
43 class MyCallable implements Callable<Object> {  
44 private String taskNum;  
45   
46 MyCallable(String taskNum) {  
47    this.taskNum = taskNum;  
48 }  
49   
50 public Object call() throws Exception {  
51    System.out.println(">>>" + taskNum + "任務啓動");  
52    Date dateTmp1 = new Date();  
53    Thread.sleep(1000);  
54    Date dateTmp2 = new Date();  
55    long time = dateTmp2.getTime() - dateTmp1.getTime();  
56    System.out.println(">>>" + taskNum + "任務終止");  
57    return taskNum + "任務返回運行結果,當前任務時間【" + time + "毫秒】";  
58 }  
59 }  

 

代碼說明:
上述代碼中Executors類,提供了一系列工廠方法用於創先線程池,返回的線程池都實現了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads) 
建立固定數目線程的線程池。
public static ExecutorService newCachedThreadPool() 
建立一個可緩存的線程池,調用execute 將重用之前構造的線程(若是線程可用)。若是現有線程沒有可用的,則建立一個新線程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。
public static ExecutorService newSingleThreadExecutor() 
建立一個單線程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
建立一個支持定時及週期性的任務執行的線程池,多數狀況下可用來替代Timer類。
ExecutoreService提供了submit()方法,傳遞一個Callable,或Runnable,返回Future。若是Executor後臺線程池尚未完成Callable的計算,這調用返回Future對象的get()方法,會阻塞直到計算完成。

二:補充說明

       在繼承Thread類實現多線程時,咱們建立了三個不一樣的對象,因此建立的三個線程其實是完成的三個不一樣的任務,因此纔會相互獨立的完成;而經過實現Runable接口來實現多線程時,咱們只建立了一個對象,而後實例化三個不一樣的線程去完成這個任務,因此至關因而共同完成任務。

Thread類也是實現Runnable接口的:

class Thread implements Runnable {
    //… public void run() { if (target != null) { target.run(); } } }

Thread中的run方法其實就是調用的是Runnable接口的run方法。

Reference:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html

相關文章
相關標籤/搜索