Java併發——ThreadPoolExecutor詳解(二)

工廠ThreadFactory+execute()+UncaughtExceptionHandler處理異常

public class Run4 {
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 99999, 9999L,
                TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        pool.setThreadFactory(new MyThreadFactory());
        pool.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
            String abc = null;
            abc.indexOf(0);
            System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
        });
    }
}

class MyThreadFactory implements ThreadFactory{

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setName("我的線程名稱:" + new Date());
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("自定義處理異常啓動:" + t.getName() + " " + e.getMessage());
                e.printStackTrace();
            }
        });
        return thread;
    }
}

在這裏插入圖片描述

set/getRejectedExecutionHandler()

方法setRejectedExecutionHandler()和getRejectedExecutionHandler()的作用是可以處理任務被拒絕執行時的行爲。

public class MyRunnable3 implements Runnable {
    private String username;

    public MyRunnable3(String username) {
        this.username = username;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
            Thread.sleep(4000);
            System.out.println(Thread.currentThread().getName() + " " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        MyRunnable3 r1 = new MyRunnable3("111");
        MyRunnable3 r2 = new MyRunnable3("222");
        MyRunnable3 r3 = new MyRunnable3("333");
        MyRunnable3 r4 = new MyRunnable3("444");
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 999L,
                TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        pool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println(((MyRunnable3)r).username + "被拒絕執行");
            }
        });
        pool.execute(r1);
        pool.execute(r2);
        pool.execute(r3);
        pool.execute(r4);
    }
}

在這裏插入圖片描述

allowsCoreThreadTimeOut()/(boolean)

方法allowsCoreThreadTimeOut()和allowsCoreThreadTimeOut(boolean value) 的作用是配置核心線程是否有超時的效果。

public class Run5 {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 5, 5,
                TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        System.out.println(pool.allowsCoreThreadTimeOut());
        for (int i = 0; i < 4; i++) {
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "begin " + System.currentTimeMillis());
                System.out.println(Thread.currentThread().getName() + "end " + System.currentTimeMillis());
            });
        }
        Thread.sleep(4000);
        System.out.println(pool.getPoolSize());
    }
}

核心線程未超時銷燬
在這裏插入圖片描述

public class Run5 {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 5, 5,
                TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        pool.allowCoreThreadTimeOut(true);
        System.out.println(pool.allowsCoreThreadTimeOut());
        for (int i = 0; i < 4; i++) {
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "begin " + System.currentTimeMillis());
                System.out.println(Thread.currentThread().getName() + "end " + System.currentTimeMillis());
            });
        }
        Thread.sleep(4000);
        System.out.println(pool.getPoolSize());
    }
}

核心線程超時銷燬:
在這裏插入圖片描述

prestartCoreThread()和prestartAllCoreThreads()

方法 prestartCoreThread每調用一次就創建一個核心線程,返回值爲 boolean,含義是是否啓動了

public class Run6 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("打印了!begin " + Thread.currentThread().getName());
                    Thread.sleep(4000);
                    System.out.println("打印了!end " + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 2, 5,
                TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        System.out.println("線程池中的線程數A:" + pool.getPoolSize());
        System.out.println("Z1=" + pool.prestartCoreThread());
        System.out.println("線程池中的線程數B:" + pool.getPoolSize());
        System.out.println("Z2=" + pool.prestartCoreThread());
        System.out.println("線程池中的線程數C:" + pool.getPoolSize());
        System.out.println("Z3=" + pool.prestartCoreThread());//無效代碼
        System.out.println("Z4=" + pool.prestartCoreThread());//無效代碼
        System.out.println("Z5=" + pool.prestartCoreThread());//無效代碼
        System.out.println("Z6=" + pool.prestartCoreThread());//無效代碼
        System.out.println("線程池中的線程數D:" + pool.getPoolSize());
    }
}

在這裏插入圖片描述
方法 prestartAllCoreThreads的作用是啓動全部核心線程,返回值是啓動核心線程的數量。

public class Run6 {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("打印了!begin " + Thread.currentThread().getName());
                    Thread.sleep(4000);
                    System.out.println("打印了!end " + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 2, 5,
                TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        System.out.println("線程池中的線程數A:" + pool.getPoolSize());
        System.out.println("啓動核心線程數量爲:" + pool.prestartAllCoreThreads());
        System.out.println("線程池中的線程數B:" + pool.getPoolSize());
    }
}

在這裏插入圖片描述

getCompletedTaskCount()

取得已經執行完成的任務數。

ThreadPoolExecutor的拒絕策略

線程池中的資源全部被佔用的時候,對新添加的Task任務有不同的處理策略,在默認的情況下, ThreadPoolExecutor類中有4種不同的處理方式:

  • AbortPolicy:當任務添加到線程池中被拒絕時,它將拋出 RejectedExecution Exception異常。
  • CallerrunsPolicy:當任務添加到線程池中被拒絕時,會使用調用線程池的 Thread線程對象處理被拒絕的任務。
  • DiscardOldestPolicy:當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然後將被拒絕的任務添加到等待隊列中。
  • DiscardPolicy:當任務添加到線程池中被拒絕時,線程池將丟棄被拒絕的任務。

AbortPolicy:
AbortPolicy策略是當任務添加到線程池中被拒絕時,它將拋出 RejectedExecutionException異常。

public class AbortDemo {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " run end!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 5,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), new ThreadPoolExecutor.AbortPolicy());
        pool.execute(runnable);//不報錯 立即在覈心線程運行
        pool.execute(runnable);//不報錯 立即在覈心線程運行
        pool.execute(runnable);//不報錯 未超過最大線程數,創建一個新線程運行
        pool.execute(runnable);//不報錯 放入隊列
        pool.execute(runnable);//不報錯 放入隊列
        pool.execute(runnable);//隊列滿了,報錯
    }
}

在這裏插入圖片描述

CallerRunsPolicy:
Caller Runs Policy策略是當任務添加到線程池中被拒絕時,會使用調用線程池的 Thread線程對象處理被拒絕的任務。

public class CallerRunsDemo {
    public static void main(String[] args) {
        MyThreadA a = new MyThreadA();
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 5,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>(2), new ThreadPoolExecutor.CallerRunsPolicy());
        System.out.println("a begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        pool.execute(a);
        pool.execute(a);
        pool.execute(a);
        pool.execute(a);
        pool.execute(a);
        pool.execute(a);
        System.out.println("a end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
    }
}

class MyThreadA extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
            System.out.println("end" + Thread.currentThread().getName() + " " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上面的實驗中,線程main被阻塞,嚴重影響程序
的運行效率,所以並不建議這樣做.
在這裏插入圖片描述

DiscardOldestPolicy:
DiscardOldestPolicy策略是當任務添加到線程池中被
拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然
後將被拒絕的任務添加到等待隊列中。

public class DiscardOldestDemo {
    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(2);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 5,
                TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy());
        for (int i = 0; i < 5; i++) {
            MyThreadD r = new MyThreadD("Runnable" + (i + 1));
            executor.execute(r);
        }
        Thread.sleep(50);
        Iterator iterator = queue.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(((MyThreadD)next).getUsername());
        }
        executor.execute(new MyThreadD("Runnable6"));
        executor.execute(new MyThreadD("Runnable7"));
        iterator = queue.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(((MyThreadD)next).getUsername());
        }
    }
}


class MyThreadD extends Thread {
    private String username;

    public MyThreadD(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public void run() {
        try {
            System.out.println(username + " run");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在這裏插入圖片描述

DiscardPolicy:
DiscardPolicy策略是當任務添加到線程池中被拒絕時,線程池將丟棄被拒絕的任務。

public class DiscardDemo {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " run end!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ArrayBlockingQueue queue = new ArrayBlockingQueue(2);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 5,
                TimeUnit.SECONDS, queue, new ThreadPoolExecutor.DiscardPolicy());
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        executor.execute(runnable);
        Thread.sleep(10000);
        System.out.println(executor.getPoolSize() + " " + queue.size());
    }
}

在這裏插入圖片描述

afterExecute()和beforeExecute()

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

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

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

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

    public static void main(String[] args) {
        MyPool pool = new MyPool(2, 2, Integer.MAX_VALUE,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>(), new AbortPolicy());
        pool.execute(() -> {
            System.out.println("執行中...");
        });
    }
}

在這裏插入圖片描述

remove(Runnable)

方法 remove( Runnable)可以刪除尚未被執行的Runnable任務。

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " begin");
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 10,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        executor.execute(runnable);

        Thread.sleep(1000);
        executor.remove(runnable);
        System.out.println("任務正在運行不能刪除...");
    }
}

正在執行的任務不能刪除
在這裏插入圖片描述

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " begin");
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " begin");
                    Thread.sleep(5000);
                    System.out.println(Thread.currentThread().getName() + " end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 10,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        executor.execute(runnable);
        executor.execute(runnable2);

        Thread.sleep(1000);
        executor.remove(runnable2);
    }
}

executor()方法提交的且並未執行的任務可以刪除。
在這裏插入圖片描述
注意:submit()方法提交的任務,無論是否正在執行,都不可以刪除!!!!

多個get方法

getActiveCount():
方法 getActive Counto的作用是取得有多少個線程正在執行任務。

getCompletedTaskCount():
方法 getCompleted Task Count0的作用是取得有多少個線程已經執行完任務了。

getCorePoolSize():
方法 getCorePoolSize的作用是取得構造方法傳入的 core Poolsize參數值。

getMaximumPoolSize():
方法 getMaximum PoolSize O的作用是取得構造方法傳入的 maximum PoolSize參數值。

getPoolSize():
方法 getPoolSize O的作用是取得池中有多少個線程。

getTaskCount():
方法 getTask Count0的作用是取得有多少個任務發送給了線程池。

ThreadPoolExecutor與Runnable執行爲亂序特性

接口 Runnable在 Thread PoolExecutor的隊列中是按順序取出,執行卻是亂序的。

public class Test2 {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 10,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        for (int i = 0; i < 50; i++) {
            MyThreadE t = new MyThreadE("username" + (i + 1));
            executor.execute(t);
        }
    }
}

class MyThreadE extends Thread {
    private String username;

    public MyThreadE(String username) {
        this.username = username;
    }

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

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章