Java線程池例子

jopen 9年前發布 | 5K 次閱讀 Java

在做很多高并發應用的時候,單線程的瓶頸已經滿足不了我們的需求,此時使用多線程來提高處理速度已經是比較常規的方案了。在使用多線程的時候,我們可以使用線程池來管理我們的線程,至于使用線程池的優點就不多說了。

對于多線程的線程安全處理,這個也非常重要,有些同學還是要多補補課。

Java線程池說起來也簡單,簡單說下繼承關系:
ThreadPoolExecutor extends AbstractExecutorService implements ExecutorService extends Executor

還有一個支持延時執行線程和可以重復執行線程的實現類:
ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService

大家把這些類中的相關方法弄清楚,使用線程池就不在話下了。其實弄清楚里面各個方法的功能也就夠了。
最重要的還是在實踐中總結經驗,企業需要的是能實際解決問題的人。

下面是我寫的一個例子,包括3個Java文件,分別是:
ExecutorServiceFactory.java
ExecutorProcessPool.java
ExecutorTest.java

下面貼出代碼:
1、ExecutorServiceFactory.java

package com.test.threadpool;

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger;

/**

  • 線程池構造工廠 *
  • @author SHANHY(365384722@QQ.COM)
  • @date 2015年12月4日 */ public class ExecutorServiceFactory { private static ExecutorServiceFactory executorFactory = new ExecutorServiceFactory(); /**

    • 定時任務線程池 */ private ExecutorService executors;

      private ExecutorServiceFactory() { }

      /**

    • 獲取ExecutorServiceFactory
    • @return */ public static ExecutorServiceFactory getInstance() { return executorFactory; }

      /**

    • 創建一個線程池,它可安排在給定延遲后運行命令或者定期地執行。
    • @return / public ExecutorService createScheduledThreadPool() { // CPU個數 int availableProcessors = Runtime.getRuntime().availableProcessors(); // 創建 executors = Executors.newScheduledThreadPool(availableProcessors 10, getThreadFactory()); return executors; }

      /**

    • 創建一個使用單個 worker 線程的
    • Executor,以無界隊列方式來運行該線程。(注意,如果因為在關閉前的執行期間出現失敗而終止了此單個線程,
    • 那么如果需要,一個新線程將代替它執行后續的任務)。可保證順序地執行各個任務,并且在任意給定的時間不會有多個線程是活動的。與其他等效的
    • newFixedThreadPool(1) 不同,可保證無需重新配置此方法所返回的執行程序即可使用其他的線程。
    • @return */ public ExecutorService createSingleThreadExecutor() { // 創建 executors = Executors.newSingleThreadExecutor(getThreadFactory()); return executors; }

      /**

    • 創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。對于執行很多短期異步任務的程序而言,這些線程池通常可提高程序性能。調用
    • execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程并添加到池中。終止并從緩存中移除那些已有 60
    • 秒鐘未被使用的線程。因此,長時間保持空閑的線程池不會使用任何資源。注意,可以使用 ThreadPoolExecutor
    • 構造方法創建具有類似屬性但細節不同(例如超時參數)的線程池。
    • @return */ public ExecutorService createCachedThreadPool() { // 創建 executors = Executors.newCachedThreadPool(getThreadFactory()); return executors; }

      /**

    • 創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。在任意點,在大多數 nThreads
    • 線程會處于處理任務的活動狀態。如果在所有線程處于活動狀態時提交附加任務
    • ,則在有可用線程之前,附加任務將在隊列中等待。如果在關閉前的執行期間由于失敗而導致任何線程終止
    • ,那么一個新線程將代替它執行后續的任務(如果需要)。在某個線程被顯式地關閉之前,池中的線程將一直存在。
    • @return */ public ExecutorService createFixedThreadPool(int count) { // 創建 executors = Executors.newFixedThreadPool(count, getThreadFactory()); return executors; }
/**
 * 獲取線程池工廠
 * 
 * @return
 */
private ThreadFactory getThreadFactory() {
    return new ThreadFactory() {
        AtomicInteger sn = new AtomicInteger();
        public Thread newThread(Runnable r) {
            SecurityManager s = System.getSecurityManager();
            ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            Thread t = new Thread(group, r);
            t.setName("任務線程 - " + sn.incrementAndGet());
            return t;
        }
    };
}

}</pre>
2、ExecutorProcessPool.java

package com.test.threadpool;

import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future;

/**

  • 線程處理類 *
  • @author SHANHY(365384722@QQ.COM)
  • @date 2015年12月4日 */ public class ExecutorProcessPool {

    private ExecutorService executor; private static ExecutorProcessPool pool = new ExecutorProcessPool(); private final int threadMax = 10;

    private ExecutorProcessPool() {

     System.out.println("threadMax>>>>>>>" + threadMax);
     executor = ExecutorServiceFactory.getInstance().createFixedThreadPool(threadMax);
    

    }

    public static ExecutorProcessPool getInstance() {

     return pool;
    

    }

    /**

    • 關閉線程池,這里要說明的是:調用關閉線程池方法后,線程池會執行完隊列中的所有任務才退出
    • @author SHANHY
    • @date 2015年12月4日 */ public void shutdown(){ executor.shutdown(); }

      /**

    • 提交任務到線程池,可以接收線程返回值
    • @param task
    • @return
    • @author SHANHY
    • @date 2015年12月4日 */ public Future<?> submit(Runnable task) { return executor.submit(task); }

      /**

    • 提交任務到線程池,可以接收線程返回值
    • @param task
    • @return
    • @author SHANHY
    • @date 2015年12月4日 */ public Future<?> submit(Callable<?> task) { return executor.submit(task); }

      /**

    • 直接提交任務到線程池,無返回值
    • @param task
    • @author SHANHY
    • @date 2015年12月4日 */ public void execute(Runnable task){ executor.execute(task); }

}</pre>
3、ExecutorTest.java

package com.test.threadpool;

import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit;

/**

  • 測試類 *
  • @author SHANHY(365384722@QQ.COM)
  • @date 2015年12月4日 */ public class ExecutorTest {

    public static void main(String[] args) {

     ExecutorProcessPool pool = ExecutorProcessPool.getInstance();
    
     for (int i = 0; i < 200; i++) {
         Future<?> future = pool.submit(new ExcuteTask1(i+""));
    

    // try { // 如果接收線程返回值,future.get() 會阻塞,如果這樣寫就是一個線程一個線程執行。所以非特殊情況不建議使用接收返回值的。 // System.out.println(future.get());
    // } catch (Exception e) { // e.printStackTrace(); // }

     }
    
     for (int i = 0; i < 200; i++) {
         pool.execute(new ExcuteTask2(i+""));
     }
    
     //關閉線程池,如果是需要長期運行的線程池,不用調用該方法。
     //監聽程序退出的時候最好執行一下。
     pool.shutdown();
    

    }

    /**

    • 執行任務1,實現Callable方式 *
    • @author SHANHY(365384722@QQ.COM)
    • @date 2015年12月4日 */ static class ExcuteTask1 implements Callable<String> { private String taskName;

      public ExcuteTask1(String taskName) {

       this.taskName = taskName;
      

      }

      @Override public String call() throws Exception {

       try {
      

      // Java 6/7最佳的休眠方法為TimeUnit.MILLISECONDS.sleep(100); // 最好不要用 Thread.sleep(100);

           TimeUnit.MILLISECONDS.sleep((int)(Math.random() * 1000));// 1000毫秒以內的隨機數,模擬業務邏輯處理
       } catch (Exception e) {
           e.printStackTrace();
       }
       System.out.println("-------------這里執行業務邏輯,Callable TaskName = " + taskName + "-------------");
       return ">>>>>>>>>>>>>線程返回值,Callable TaskName = " + taskName + "<<<<<<<<<<<<<<";
      

      } }

      /**

    • 執行任務2,實現Runable方式 *
    • @author SHANHY(365384722@QQ.COM)
    • @date 2015年12月4日 */ static class ExcuteTask2 implements Runnable { private String taskName;

      public ExcuteTask2(String taskName) {

       this.taskName = taskName;
      

      }

      @Override public void run() {

       try {
           TimeUnit.MILLISECONDS.sleep((int)(Math.random() * 1000));// 1000毫秒以內的隨機數,模擬業務邏輯處理
       } catch (Exception e) {
           e.printStackTrace();
       }
       System.out.println("-------------這里執行業務邏輯,Runnable TaskName = " + taskName + "-------------");
      

      }

      } }</pre>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!