歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java中的多線程

  簡介

  為了給並發程序開發提供更好的支持,Java不僅提供了Thread類、Runnable接口等簡單的多線程支持工具,還提供了用於多線程管理的線程池,用於提高並發程序的性能。

無限制線程的缺陷

  多線程的軟件設計方法確實可以提高多核處理器的計算能力,提高系統的性能和吞吐量,但是如果不加限制的使用多線程,對於系統性能不僅不能提升,反而會下降產生不利影響。

  簡單的線程創建方法new Thread().start(),通過thread來啟動線程,並且由系統自動的回收線程。在簡單的系統這樣做並沒有問題,但是在真實的生產系統中,在某一時刻會有大量的請求,這樣就需要為每一個請求創建一個線程,而當線程數量過大時,會耗盡CPU和內存資源。

  雖然線程是一種輕量級的工具,但是其創建和銷毀也需要消耗一定的時間;其次,線程本身也是需要占用內存空間的,大量的線程會搶占內存只有,導致Out of memory異常,並且大量線程的回收會給GC帶來很大壓力,延長GC停頓的時間。

  因此,對線程的使用必須控制一個度,在適當的范圍內使用會提供系統性能,但是,一旦超過了這個范圍,大量的線程就會拖垮整個系統。在生產環境下,必須要對其進行管理和控制。

簡單線程池的實現

  前面介紹在多線程中不斷的創建和銷毀線程會帶來額外的開銷,這樣就需要引入一種線程復用機制,即線程池。線程池的基本功能就是進行線程復用,當系統接受一個提交的任務,需要一個線程時,並不急於去創建一個線程,而是去現場池中尋找,是否有閒置的線程,若有,直接使用線程池中的線程工作,如沒有,再去創建新的線程。待任務完成後,也不是簡單的銷毀線程,而是將線程放回線程池中,以便下次復用。

  上面已經把線程池實現的原理簡單說明了一下,下面我們自己實現一個線程,來了解一下線程池實現的核心功能,有助於理解線程池的實現。

  線程池實現代碼:

public class ThreadPool {
    private static ThreadPool instance = null;
    //空閒線程隊列
    private List<PThread> idelThreads;
    //已有的線程總數
    private int threadCounter;
    private boolean isShutdown = false;
   
    public ThreadPool() {
        idelThreads = new Vector<PThread>(5);
        threadCounter=0;
    }

    public synchronized int getCreatedThreadsCount() {
       
        return threadCounter;
    }
   
    //取得線程池實例
    public synchronized static ThreadPool getInstatce(){
        if(instance==null){
            instance = new ThreadPool();
        }
        return instance;
    }
   
    //把線程重新放回到池中
   
    public synchronized void repool(PThread repoolThread){
        if(!isShutdown){
            idelThreads.add(repoolThread);
        }else{
            repoolThread.shutdown();
        }
    }
   
    //停止池中所有線程
    public synchronized void shutdown(){
        isShutdown = true;
        for (int i = 0; i < idelThreads.size(); i++) {
            PThread pthread = idelThreads.get(i);
            pthread.shutdown();
        }
    }
    //執行任務
    public synchronized void start(Runnable target){
        PThread pthread = null;
        //如果有閒置線程
        if(idelThreads.size()>0){
            int index = idelThreads.size()-1;
            pthread=idelThreads.get(index);
            idelThreads.remove(index);
            pthread.setTarget(target);
        }else{//如果沒有閒置線程
            threadCounter++;
            PThread p = new PThread(instance, target, "PThread#"+threadCounter);
            p.start();
        }
    }
   
   
   
}

  從代碼中可以看出,線程池中有一個閒置線程的隊列,在執行任務時,如果有閒置線程,則從線程池中取線程執行任務,如果沒有現在線程,則創建新的線程,並且在現場使用完畢後,會將線程重新放回到閒置線程隊列中。

  另外,線程池的使用還需要一個永不退出的線程的配合使用,該線程在手動關閉前永不結束,並且一直等待新任務的到來。代碼如下:

public class PThread extends Thread{
    //線程池
    private ThreadPool pool;
    //任務
    private Runnable target;
    private boolean isShutDown = false;
    private boolean isIdle = false;
    public PThread(ThreadPool pool, Runnable target,String name) {
        super(name);
        this.pool = pool;
        this.target = target;
    }
   
    public synchronized Runnable getTarget() {
        return target;
    }
    public synchronized boolean isIdle() {
        return isIdle;
    }

    @Override
    public void run() {
       
        while(!isShutDown){
            isIdle = false;
           
            if(target!=null){
                //運行任務
                target.run();
            }
            //任務結束,閒置任務
            isIdle=true;
           
            try {
                pool.repool(this);
                synchronized (this) {
                    //線程閒置,等待任務到來
                    wait();
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
           
            isIdle=false;
        }
   
    }
   
    public synchronized void setTarget(Runnable target){
        this.target=target;
        //設置任務之後,通知run方法,開始執行
        notifyAll();
    }
   
    public synchronized void shutdown(){
        isShutDown=true;
        notifyAll();
    }
   
   
}

執行線程:

public class MyThread implements Runnable{
   
   
    private String name;
   
   
   
    public MyThread() {
       
    }


    public MyThread(String name) {
        this.name = name;
    }


    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
   
}

測試代碼:

public class TestClient {
    public static void main(String[] args) {
       
        ExecutorService executor = Executors.newCachedThreadPool();
       
        long begin = System.currentTimeMillis();
       
        for (int i = 0; i < 1000; i++) {
            //new Thread(new MyThread("testnopoolThread"+i)).start();
           
            ThreadPool.getInstatce().start(new MyThread("testpoolThread"+i));
           
            //executor.execute(new MyThread("executorpoolThread"+i));
        }
       
        System.out.println(System.currentTimeMillis()-begin);
   
    }
}

   線程池能減少線程頻繁調度的開銷,線程的復用,對系統性能的提升效果比較明顯。

•Executor框架

  JDK提供了一整套的Executor框架,幫助開發人員有效的進行線程控制。ThreadPoolExecutor表示一個線程池,Executors類扮演著線程池工廠的角色,通過Executor可以取得一個特定功能的線程池。

  newFixedThreadPool():該方法返回一個固定線程數量的線程池,該線程池中線程的數量始終保持不變。當一個任務提交後,線程池中若有空閒線程則立即執行,若沒有,新任務會被保存在一個任務隊列中,待有現車空閒時,便處理任務隊列中的任務。

  newSingleThreadExecutor():該方法返回只有一個線程的線程池。若多余的任務被提交到該線程池,任務會被保存到一個任務隊列中,若線程空閒,按先進先出的順序執行隊列中的任務。

  newCacheThreadPool():該方法返回一個根據實際情況調整線程數量的線程池。若有空閒線程可以復用,則優先選擇使用可復用的線程,否則,創建新的線程處理新任務。

  newSingleThreadScheduledExecutor()方法:該方法返回一個ScheduledExecutorService對象,線程池大小為1,在給定時間內執行某一任務。

•自定義線程池

  newFixedThreadPool、newSingleThreadExecutor、newCacheThreadPool的內部實現都實現了ThreadPoolExecutor。在ThreadPoolExecutor中有一個最主要的構造函數:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2016-03/129622p2.htm

Copyright © Linux教程網 All Rights Reserved