Java建立多線程的四種方式

在進行講解線程的建立方式以前,首先了解下什麼是進程,什麼是線程,進程與線程之間的關係等java

什麼是進程?緩存

其實當一個程序進入內存運行時,就是一個進程,進程是處於運行中的程序,而且具備必定的獨立功能,進程是系統進行資源分配和調度的一個獨立單位,具備獨立性,動態性,併發性,這裏的獨立性指的是在系統中獨立存在,有獨立資源,有獨立地址空間,沒有進程容許,不會跟別的進程交互;動態性指的是進程在系統中有生命週期以及各類不一樣的狀態,這也是跟程序的區別,進程加入了時間的概念;併發性指的是進程間能夠在單處理器上併發執行,獨立互不影響多線程

那什麼是線程呢?併發

多線程其實就是擴展了多進程的概念,使一個進程能夠同時併發處理多個任務,能夠當作是輕量級的進程;線程是進程的組成部分,一個進程能夠有多個線程,線程能夠有本身的堆棧,程序計數器,局部變量,可是沒有系統資源,線程是必須有一個父進程的,他與父進程的其餘線程是共享所有資源,線程的調度與管理是由父進程負責爲完成框架

簡單來講就是,操做系統能夠同時執行多個任務,每一個任務就是進程,進程能夠同時執行多個任務,每一個任務就是線程異步

如何建立多線程?ide

建立多線程的方式能夠歸納爲四種:學習

1,繼承Thread類,重寫run()方法spa

2,實現Runnable接口,重寫run()方法操作系統

3,實現Callable接口, 重寫call()方法,藉助Future執行

4,藉助Executor框架使用線程池建立線程

具體線程建立方式以下:

一:繼承Thread類建立線程

class MyThead extends  Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ": 繼承Thread線程啦");
    }
}

調用線層的start()方法啓動線程

 new MyThead().start();

執行結果以下:

 

 

 注:Thread其實也是實現了Runnable接口

二:實現Runnable接口建立線程

class MyRunnable implements  Runnable {
    public void run() {
        System.out.println(Thread.currentThread().getName() + ": 實現Runnable線程啦");
    }
}

  藉助Thread類調用線層的start()方法啓動線程

new Thread(new MyRunnable()) .start();

 執行結果以下: 

 

三:使用Callable和Future接口建立線程

Java5開始提供Callable接口,提供call方法做爲線程的執行體,能夠當作是Runnable接口的加強版本,加強點在於call()方法能夠有返回值,而且能夠拋出異常,因爲Callable是新增的接口,不能做爲Thread的target使用,因此Java5裏提供了Future接口,該接口實現了Runnable,Future的實現類FutureTask類用來包裝Callable對象,那麼該怎麼調用並獲取返回值呢?下面用代碼進行展現用法:

建立Callable對象

class MyCallable  implements Callable<Map<String, String>> {

    public Map<String, String> call() throws Exception {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("returnCode", "000000");
        map.put("messgae", Thread.currentThread().getName() + ":Callable建立線程成功");
        return map;
    }
}

 啓動線程

public static void main(String[] args) {
        FutureTask<Map<String, String>>  future = new FutureTask(new MyCallable());
        new Thread(future).start();
        try {
            /**
             * get()返回Callable任務裏的call()返回值
             * get方法是一個阻塞方法,對於task內置了一些任務狀態,當任務狀態爲新建0或者初始化完成的時候1的時候會阻塞
             * 須要根據設置的時間阻塞,沒有設置時會一直進行阻塞,一直到有結果返回
             */
            Map<String, String> resultMap = future.get();
            System.out.println(resultMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

執行結果以下:

 

 

 

四:藉助Executor框架使用線程池建立線程

  •  Executors提供了一系列工廠方法用於創先線程池,建立的線程池都實現了ExecutorService接口,下面爲經常使用的線程池:

建立固定數目線程的線程池,操做一個共享的無邊界隊列,當全部線程都處於活動狀態時,額外的任務被提交它們將在隊列中等待,直到線程可用。當有線程池掛掉會從新建立一個新的

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
 }
 
  • 建立一個可緩存的線程池,能夠建立的範圍是0-Integer.MAX_VALUE,當有可用線程時直接使用,當沒有時建立新的線程並添加到緩存中,提供使用,這種類型的線程池,適合執行許多短時間的異步任務的程序,是在執行方法以前建立線程,60秒內未使用的線程會被終止並刪除緩存,
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
 
  • 建立一個單線程化的Executor,只會有一個線程池,當這個線程池掛掉會自動建立一個新的
 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
  }
  • 建立一個支持定時及週期性的任務執行的線程池,多數狀況下可用來替代Timer類
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
 }
 
通常來講,CachedTheadPool在程序執行過程當中一般會建立與所需數量相同的線程,而後在它回收舊線程時中止建立新線程,所以它是合理的Executor的首選,只有當這種方式會引起問題時(好比須要大量長時間面向鏈接的線程時),才須要考慮用FixedThreadPool
 
下面提供一個固定大小的線程池的使用案例:
    public static void main(String[] args) {
        try {
            ExecutorService threadPool = Executors.newFixedThreadPool(10);
            for (int i = 0; i <15; i++) {
          //主要經過submit方法執行調用,能夠接收Runnable,Callable Future<Map<String, String>> future = threadPool.submit(new MyCallable()); Map<String, String> resultMap = future.get(); System.out.println(resultMap); } threadPool.shutdown(); } catch (Exception e) { e.printStackTrace(); } }
 
執行結果以下:

 

 

下一篇再介紹相關線程的其餘知識,歡迎討論,一塊兒學習

相關文章
相關標籤/搜索