java並發編程(2)線程池的使用

來源:互聯網
上載者:User

標籤:cycle   res   Factory 方法   instance   ever   工廠   roc   資料庫連接   也會   

一、任務和執行策略之間的隱性耦合

  Executor可以將任務的提交和任務的執行策略解耦

  只有任務是同類型的且執行時間差別不大,才能發揮最大效能,否則,如將一些耗時間長度的任務和耗時短的任務放在一個線程池,除非線程池很大,否則會造成死結等問題

1.線程饑餓死結

  類似於:將兩個任務提交給一個單線程池,且兩個任務之間相互依賴,一個任務等待另一個任務,則會發生死結;表現為池不夠

  定義:某個任務必須等待池中其他任務的運行結果,有可能發生饑餓死結

2.線程池大小

  

  注意:線程池的大小還受其他的限制,如其他資源集區:資料庫連接池

    如果每個任務都是一個串連,那麼線程池的大小就受制於資料庫連接池的大小

3.配置ThreadPoolExecutor線程池

執行個體:

  1.通過Executors的Factory 方法返回預設的一些實現

  2.通過執行個體化ThreadPoolExecutor(.....)自訂實現

線程池的隊列

  1.無界隊列:任務到達,線程池飽滿,則任務在隊列中等待,如果任務無限達到,則隊列會無限擴張

    如:單例和固定大小的線程池用的就是此種

  2.有界隊列:如果新任務到達,隊列滿則使用飽和策略

    3.同步移交:如果線程池很大,將任務放入隊列後在移交就會產生延時,如果任務生產者很快也會導致任務排隊

    SynchronousQueue直接將任務移交給背景工作執行緒

    機制:將一個任務放入,必須有一個線程等待接受,如果沒有,則新增線程,如果線程飽和,則拒絕任務

    如:CacheThreadPool就是使用的這種策略

飽和策略:

  setRejectedExecutionHandler來修改飽和策略

  1.終止Abort(預設):拋出異常由調用者處理

  2.拋棄Discard

  3.拋棄DiscardOldest:拋棄最舊的任務,注意:如果是優先順序隊列將拋棄優先順序最高的任務

  4.CallerRuns:回退任務,有調用者線程自行處理

4.線程工廠ThreadFactoy

   每當建立線程時:其實是調用了線程工廠來完成

   自訂線程工廠:implements ThreadFactory

   可以定製該線程工廠的行為:如UncaughtExceptionHandler等

  

public class MyAppThread extends Thread {    public static final String DEFAULT_NAME = "MyAppThread";    private static volatile boolean debugLifecycle = false;    private static final AtomicInteger created = new AtomicInteger();    private static final AtomicInteger alive = new AtomicInteger();    private static final Logger log = Logger.getAnonymousLogger();    public MyAppThread(Runnable r) {        this(r, DEFAULT_NAME);    }    public MyAppThread(Runnable runnable, String name) {        super(runnable, name + "-" + created.incrementAndGet());        //設定該線程工廠建立的線程的 未捕獲異常的行為        setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {            public void uncaughtException(Thread t,                                          Throwable e) {                log.log(Level.SEVERE,                        "UNCAUGHT in thread " + t.getName(), e);            }        });    }    public void run() {        // Copy debug flag to ensure consistent value throughout.        boolean debug = debugLifecycle;        if (debug) log.log(Level.FINE, "Created " + getName());        try {            alive.incrementAndGet();            super.run();        } finally {            alive.decrementAndGet();            if (debug) log.log(Level.FINE, "Exiting " + getName());        }    }    public static int getThreadsCreated() {        return created.get();    }    public static int getThreadsAlive() {        return alive.get();    }    public static boolean getDebug() {        return debugLifecycle;    }    public static void setDebug(boolean b) {        debugLifecycle = b;    }}

 

5.擴充ThreadPoolExecutor

  可以被自訂子類覆蓋的方法:

  1.afterExecute:結束後,如果拋出RuntimeException則方法不會執行

  2.beforeExecute:開始前,如果拋出RuntimeException則任務不會執行

  3.terminated:線上程池關閉時,可以用來釋放資源等

 

二、遞迴演算法的並行化

1.迴圈  

  在迴圈中,每次迴圈操作都是獨立的

//序列化    void processSequentially(List<Element> elements) {        for (Element e : elements)            process(e);    }    //並行化    void processInParallel(Executor exec, List<Element> elements) {        for (final Element e : elements)            exec.execute(new Runnable() {                public void run() {                    process(e);                }            });    }

 

2.迭代

    如果每個迭代操作是彼此獨立的,則可以串列執行

  如:深度優先搜尋演算法;注意:遞迴還是串列的,但是,每個節點的計算是並行的

  

//串列 計算compute 和串列迭代    public <T> void sequentialRecursive(List<Node<T>> nodes, Collection<T> results) {        for (Node<T> n : nodes) {            results.add(n.compute());            sequentialRecursive(n.getChildren(), results);        }    }    //並行 計算compute 和串列迭代    public <T> void parallelRecursive(final Executor exec, List<Node<T>> nodes, final Collection<T> results) {        for (final Node<T> n : nodes) {            exec.execute(() -> results.add(n.compute()));            parallelRecursive(exec, n.getChildren(), results);        }    }    //調用並行方法的操作    public <T> Collection<T> getParallelResults(List<Node<T>> nodes)            throws InterruptedException {        ExecutorService exec = Executors.newCachedThreadPool();        Queue<T> resultQueue = new ConcurrentLinkedQueue<T>();        parallelRecursive(exec, nodes, resultQueue);        exec.shutdown();        exec.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);        return resultQueue;    }

 

  執行個體:

  

public class ConcurrentPuzzleSolver <P, M> {    private final Puzzle<P, M> puzzle;    private final ExecutorService exec;    private final ConcurrentMap<P, Boolean> seen;    protected final ValueLatch<PuzzleNode<P, M>> solution = new ValueLatch<PuzzleNode<P, M>>();    public ConcurrentPuzzleSolver(Puzzle<P, M> puzzle) {        this.puzzle = puzzle;        this.exec = initThreadPool();        this.seen = new ConcurrentHashMap<P, Boolean>();        if (exec instanceof ThreadPoolExecutor) {            ThreadPoolExecutor tpe = (ThreadPoolExecutor) exec;            tpe.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());        }    }    private ExecutorService initThreadPool() {        return Executors.newCachedThreadPool();    }    public List<M> solve() throws InterruptedException {        try {            P p = puzzle.initialPosition();            exec.execute(newTask(p, null, null));            // 等待ValueLatch中閉鎖解開,則表示已經找到答案            PuzzleNode<P, M> solnPuzzleNode = solution.getValue();            return (solnPuzzleNode == null) ? null : solnPuzzleNode.asMoveList();        } finally {            exec.shutdown();//最終主線程關閉線程池        }    }    protected Runnable newTask(P p, M m, PuzzleNode<P, M> n) {        return new SolverTask(p, m, n);    }    protected class SolverTask extends PuzzleNode<P, M> implements Runnable {        SolverTask(P pos, M move, PuzzleNode<P, M> prev) {            super(pos, move, prev);        }        public void run() {            //如果有一個線程找到了答案,則return,通過ValueLatch中isSet CountDownlatch閉鎖實現;            //為類避免死結,將已經掃描的節點放入set集合中,避免繼續掃描產生死迴圈            if (solution.isSet() || seen.putIfAbsent(pos, true) != null){                return; // already solved or seen this position            }            if (puzzle.isGoal(pos)) {                solution.setValue(this);            } else {                for (M m : puzzle.legalMoves(pos))                    exec.execute(newTask(puzzle.move(pos, m), m, this));            }        }    }}

 

  

 

java並發編程(2)線程池的使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.