[转]Java 多线程框架Executor

参考地址:

Java多线程框架Executor详解

引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。

Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

newFixedThreadPool可重用固定线程数线程池

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。

    @Test
    public void testNewFixedThreadPool() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
//            Runnable syncRunnable = new Runnable() {
//                @Override
//                public void run() {
//                    System.out.println(Thread.currentThread().getName());
//                }
//            };
//            executorService.execute(syncRunnable);
            executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
        }
    }

运行结果:总共只会创建5个线程, 开始执行五个线程,当五个线程都处于活动状态,再次提交的任务都会加入队列等到其他线程运行结束,当线程处于空闲状态时会被下一个任务复用

newCachedThreadPool可缓存线程池

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程

    @Test
    public void testCachedThreadPool() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            executorService.execute(() -> System.out.println(Thread.currentThread().getName()));
        }
    }

运行结果:可以看出缓存线程池大小是不定值,可以需要创建不同数量的线程,在使用缓存型池时,先查看池中有没有以前创建的线程,如果有,就复用.如果没有,就新建新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务

newScheduledThreadPool定时线程池

创建一个定长线程池,支持定时及周期性任务执行

延迟执行

schedule(Runnable command,long delay, TimeUnit unit)

创建并执行在给定延迟后启用的一次性操作

    @Test
    public void testNewScheduledThreadPool() throws InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            scheduledExecutorService.schedule(() ->
                    System.out.println(Thread.currentThread().getName()), 5000, TimeUnit.MILLISECONDS);
        }
        Thread.sleep(1000 * 10);
    }

运行结果和newFixedThreadPool类似,不同的是newScheduledThreadPool是延时一定时间之后才执行

定周期执行-给定周期

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)

创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推

    @Test
    public void testNewScheduledThreadPool2() throws InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            scheduledExecutorService.scheduleAtFixedRate(() ->
                    System.out.println(Thread.currentThread().getName()), 500, 300, TimeUnit.MILLISECONDS);
        }
        Thread.sleep(1000 * 50);
    }

定周期执行-给定间隔

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟

    @Test
    public void testNewScheduledTreadPool3() throws InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            scheduledExecutorService.scheduleWithFixedDelay(() ->
                    System.out.println(Thread.currentThread().getName()), 500, 300, TimeUnit.MILLISECONDS);
        }
        Thread.sleep(1000 * 50);
    }

newSingleThreadExecutor 单线程化线程池

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

    @Test
    public void testNewSingleThreadExecutor() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            int temp = i;
            executorService.execute(() -> System.out.println(temp + Thread.currentThread().getName()));
        }
    }

ThreadPoolExecutor 自定义线程池

public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)

corePoolSize 指的是保留的线程池大小

maximumPoolSize 指的是线程池的最大大小

keepAliveTime 指的是空闲线程结束的超时时间

unit 是一个枚举,表示 keepAliveTime 的单位

workQueue 表示存放任务的队列

    @Test
    public void testThreadPoolExecutor() {
        BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<>(100);
        ExecutorService executorService = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MILLISECONDS, bqueue);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> System.out.println(Thread.currentThread()));
        }
    }

线程工作过程:

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。

c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部