Java 併發編程學習筆記(14) ----ThreadPoolExecutor 線程池的方法

1.1 shutdown() 和 shutdownNow()

方法shutdown()的作用是使當前未執行完的線程繼續執行,而不再添加新的任務,
shutdown()方法是不阻塞的。
方法shutdownNow()的作用是中斷所有的任務,並且拋出InterruptdException
異常(需要和任務中的if(Thread.currentThread().isInterrupted() == true) 結合使用)。
未執行的線程不再執行,也從執行隊列中清除。

2.1 工廠ThreadFactory + UncaughtExceptionHandler 處理異常

可以通過重寫ThreadFactory 中的newThread(Runnable r)方法來對線程的一些屬性進行定製化。

2.2 代碼


package com.lhc.concurrent.executor.factory;

import java.util.Date;
import java.util.concurrent.ThreadFactory;

public class MyTHreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setName("name:" + new Date());
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("自定義處理異常");
                System.out.println(t.getName() + ":" + e.getMessage());
                e.printStackTrace();
            }
        });
        return thread;
    }
}

2.3 測試類


package com.lhc.concurrent.executor.factory;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
        //拋出異常
        String str = null;
        System.out.println(str.contains(""));
        System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
    }

    public static void main(String[] srgs){
        MyRunnable myRunnable = new MyRunnable();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 8, 20, TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>());
        executor.setThreadFactory(new MyTHreadFactory());
        executor.execute(myRunnable);
    }
}

2.4運行結果

name:Mon May 13 17:16:57 GMT+08:00 2019 1557739017491
java.lang.NullPointerException
自定義處理異常
name:Mon May 13 17:16:57 GMT+08:00 2019:null
at com.lhc.concurrent.executor.factory.MyRunnable.run(MyRunnable.java:13)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at
java.lang.Thread.run(Thread.java:745)

3.1 方法afterExecute() 和 beforeExecute()

在線程池ThreadPoolExecutor 類中重寫這兩個方法可以對線程池中執行的線程對象實現監控。

3.2 代碼


package com.lhc.concurrent.executor.before;

public class MyThread extends Thread{
    public MyThread(String name) {
        super();
        this.setName(name);
    }

    @Override
    public void run() {
        System.out.println("打印了! begin" + this.getName() + " " + System.currentTimeMillis());
        try {
            Thread.sleep(4000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("打印了! end" + this.getName() + " " + System.currentTimeMillis());
    }
}

3.3 測試類


package com.lhc.concurrent.executor.before;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool extends ThreadPoolExecutor{
    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                        BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        System.out.println(((MyThread)r).getName() + "準備執行");
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        System.out.println(((MyThread)r).getName() + "執行完畢");
    }

    public static void main(String[] args){
        MyThreadPool myThreadPool = new MyThreadPool(2, 2, Integer.MAX_VALUE,
                TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        myThreadPool.execute(new MyThread("0001"));
        myThreadPool.execute(new MyThread("0002"));
        myThreadPool.execute(new MyThread("0003"));
        myThreadPool.execute(new MyThread("0004"));
    }
}


4.1 方法execute() 與submit的區別

1) 方法execute() 沒有返回值,而submit()方法可以有返回值
2) 方法execute() 在默認的情況下異常直接拋出,不能捕獲,但可以通過自定義ThreadFactory 的方式進行捕獲,而submit()方法在默認的情況下,可以
捕獲異常。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章