java筆記--使用線程池優化多線程編程

 

使用線程池優化多線程編程html

 

認識線程池java

在Java中,全部的對象都是須要經過new操做符來建立的,
若是建立大量短生命週期的對象,將會使得整個程序的性能很是的低下。
這種時候就須要用到了池的技術,好比數據庫鏈接池,線程池等。數據庫

 

在java1.5以後,java自帶了線程池,在util包下新增了concurrent包,
這個包主要做用就是介紹java線程和線程池如何使用的。編程

 

在包java.util.concurrent下的 Executors類中定義了Executor、ExecutorService、ScheduledExecutorService、
ThreadFactoryScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。緩存

此類支持如下各類方法
    a.建立並返回設置有經常使用配置字符串的 ExecutorService 的方法。
    b.建立並返回設置有經常使用配置字符串的 ScheduledExecutorService 的方法。
    c.建立並返回「包裝的」ExecutorService 方法,它經過使特定於實現的方法不可訪問來禁用從新配置。
    d.建立並返回 ThreadFactory 的方法,它可將新建立的線程設置爲已知的狀態。
    e.建立並返回非閉包形式的 Callable 的方法,這樣可將其用於須要 Callable 的執行方法中。
   --若是朋友您想轉載本文章請註明轉載地址"http://www.cnblogs.com/XHJT/p/3897773.html "謝謝-- 
首先咱們先來比較一下用線程池建立多個線程和用獨立運行的方式建立多個線程的區別,
這裏咱們將經過比較兩種方法佔有內存和花費時間,來講明線程池的必要性重要性多線程

 

代碼實例:閉包

package com.xhj.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 比較獨立建立和線程池建立線程的優劣 比較因素--時間和佔用內存
 * 
 * @author XIEHEJUN
 * 
 */
public class CompareThreadPool implements Runnable {
    private int id = 0;

    @Override
    public void run() {
        id++;

    }

    public static void main(String[] args) {
        /**
         * 獨立建立1000個線程
         */
        {
            // 獲取當前程序運行時對象
            Runtime run = Runtime.getRuntime();
            // 調用垃圾回收機制,以減小內存偏差
            run.gc();
            // 獲取當前JVM的空閒內存
            long freeMemory = run.freeMemory();
            // 系統當前時間
            long timePro = System.currentTimeMillis();
            // 獨立建立並執行1000個線程
            for (int i = 0; i < 1000; i++) {
                new Thread(new CompareThreadPool()).start();
            }
            System.out.println("獨立建立並執行1000個線程所須要佔用的內存大小: "
                    + (freeMemory - run.freeMemory()));
            System.out.println("獨立建立並運行1000個線程須要的時間爲: "
                    + (System.currentTimeMillis() - timePro));
        }
        /**
         * 利用線程池建立1000個線程
         */
        {
            // 獲取當前程序運行時對象
            Runtime run = Runtime.getRuntime();
            // 調用垃圾回收機制,以減小內存偏差
            run.gc();
            // 獲取當前JVM的空閒內存
            long freeMemory = run.freeMemory();
            // 系統當前時間
            long timePro = System.currentTimeMillis();
            ExecutorService service = Executors.newFixedThreadPool(2);
            // 線程池建立並執行1000個線程
            for (int i = 0; i < 1000; i++) {
                service.submit(new CompareThreadPool());
            }

            System.out.println("使用線程池建立1000個線程所須要佔用的內存大小: "
                    + (freeMemory - run.freeMemory()));
            // 線程池使用完成,關閉線程池
            service.shutdown();
            System.out.println("使用線程池建立並運行1000個線程須要的時間爲: "
                    + (System.currentTimeMillis() - timePro));

        }

    }

}

結果爲:ide

 

結論--爲何要用線程池:    
    經過上面這個例子,咱們知道使用線程池能夠大大的提升系統的性能,提升程序任務的執行效率,
    節約了系統的內存空間。在線程池中,每個工做線程均可以被重複利用,可執行多個任務,
    減小了建立和銷燬線程的次數。可以根據系統的承受能力,調整其線程數目,以便使系統達到運行的最佳效果。工具

    
線程池原理:
    一個線程池中有多個處於可運行狀態的線程,當向線程池中添加Runnable或Callable接口對象時,
    就會有一個線程來執行run()方法或call()方法。若是方法執行完畢,則該線程並不終止,
    而是繼續在池中處於可運行狀態,以運行新的任務。性能

 

瞭解線程池(java中建立線程池的幾種經常使用靜態方法)

 

在java中,線程池的頂級接口是util.concurrent包下的Executors工具類,在這個類裏,定義了不少操做線程池的方法。
其中最經常使用的線程池有:
1.建立單線程的線程池:
    newSingleThreadExecutor(),建立一個只有一個線程的線程池,此單線程按照任務的提交順序執行全部的任務,
    若遇到異常中斷,線程池則會從新創建一個單線程來替代其完成後續工做。
    
    代碼實例:

    /**
     * 建立一個單線程的線程池
      * 
     * @return
     */
    public ExecutorService SingleThreadPool() {
        ExecutorService singlePool = Executors.newSingleThreadExecutor();
        return singlePool;
    }

 

2.建立一個可緩存的線程池:
    newCachedThreadPool(),
建立一個不限制大小,且只能的線程池,他會根據任務量的多少來開闢和減小內存空間,
    可是線程池中線程的大小依賴於系統的性能或者JVM的容量
    
    代碼實例:

    

 

   /**
     * 建立一個可緩存線程池
      * 
     * @return
     */
    public ExecutorService CachedThreadPool() {
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        return cachedPool;
    }

 

 

3.建立一個大小固定的線程池:
    newFixedThreadPool(),
建立一個固定大小的線程池,任務提交則創建線程,直到線程大小達到線程池容許最大值,
    若某個線程結束,線程池則補充一個新的線程。

    代碼實例:

   

   /**
     * 建立一個大小固定的線程池
      * 
     * @return
     */
    public ExecutorService FixedThreadPool() {
        ExecutorService fixedPool = Executors.newFixedThreadPool(2);
        return fixedPool;
    }


   

 

4.建立一個可定時、週期性執行的線程池
    newScheduledThreadPool(),
建立一個可定時、週期性執行的線程池,此線程池沒有大小限制,
    實現週期性任務調度。

    代碼實例:

ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1);

 

    
爲了便於你們理解和對比其不一樣之處,下面將把這幾個經常使用線程池整合到一個程序當中,

代碼實例:

 

package com.xhj.thread;

import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 幾個經常使用線程池的理解與運用
 * 
 * @author XIEHEJUN
 * 
 */
public class CreateThreadPools extends Thread {

    @Override
    public void run() {
        System.out.println("系統時間 : " + System.currentTimeMillis() + " 線程: "
                + Thread.currentThread().getName() + "正在執行!!");

    }

    /**
     * 建立一個單線程的線程池
     * 
     * @return
     */
    public ExecutorService SingleThreadPool() {
        ExecutorService singlePool = Executors.newSingleThreadExecutor();
        return singlePool;
    }

    /**
     * 建立一個大小固定的線程池
     * 
     * @return
     */
    public ExecutorService FixedThreadPool() {
        ExecutorService fixedPool = Executors.newFixedThreadPool(3);
        return fixedPool;
    }

    /**
     * 建立一個可緩存線程池
     * 
     * @return
     */
    public ExecutorService CachedThreadPool() {
        ExecutorService cachedPool = Executors.newCachedThreadPool();
        return cachedPool;
    }

    /**
     * 將建立好的線程放入線程池,並執行
     * 
     * @param pool
     */
    public void service(ExecutorService pool) {
        // 建立線程
        Thread thread1 = new CreateThreadPools();
        Thread thread2 = new CreateThreadPools();
        Thread thread3 = new CreateThreadPools();
        Thread thread4 = new CreateThreadPools();
        Thread thread5 = new CreateThreadPools();
        // 線程入線程池,並執行
        pool.execute(thread1);
        pool.execute(thread2);
        pool.execute(thread3);
        pool.execute(thread4);
        pool.execute(thread5);
        // 關閉線程池
        pool.shutdown();
    }

    /**
     * 建立一個大小無限制的線程池,可用與定時和週期性服務
     */
    public void scheduledThreadPool() {
        ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1);

        scheduledPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println("=======" + System.currentTimeMillis()
                        + "=========");
            }
        }, 1000, 5000, TimeUnit.MILLISECONDS);

        scheduledPool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println(System.nanoTime());

            }
        }, 1000, 2000, TimeUnit.MILLISECONDS);

    }

    public static void main(String[] args) {
        CreateThreadPools creatThreadPool = new CreateThreadPools();
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("請選擇建立線程池:1.單線程線程池;2.可緩存線程池;3.固定大小線程池;4可定時週期性執行線程池");
            int i = sc.nextInt();

            switch (i) {
            case 1:
                System.out.println("-----調用單線程的線程池-----");
                // 調用單線程的線程池
                creatThreadPool.service(creatThreadPool.SingleThreadPool());
                break;
            case 2:
                System.out.println("-----調用可緩存線程的線程池-----");
                // 調用可緩存線程的線程池
                creatThreadPool.service(creatThreadPool.CachedThreadPool());
                break;
            case 3:
                System.out.println("-----調用固定大小線程的線程池-----");
                // 調用固定大小線程的線程池
                creatThreadPool.service(creatThreadPool.FixedThreadPool());
                break;
            case 4:
                System.out.println("-----調用大小無限制可定時和週期性執行的線程池-----");
                // 調用固定大小線程的線程池
                creatThreadPool.scheduledThreadPool();
                break;
            }
        }
    }
}

注:當線程池任務結束以後,必定要記得將線程池關閉,執行shutdown()方法。     

相關文章
相關標籤/搜索