细说Java线程池

青春过了一大半,原来只是陪时间玩耍------第一期学习笔记!!!

Executors类的基本信息

继承实现关系------->>>>>>
public class Executors extends Object

描述----<<<<<

java.util.concurrent.包中定义的执行程序执行者服务计划执行者服务线程工厂可调用类的工厂和实用方法。此类支持以下方法:
创建和返回使用通常有用的配置设置的执行者服务的方法。
使用通常有用的配置设置创建和返回计划执行服务的方法。
创建并返回"包装"执行者服务的方法,通过使无法访问特定于实施的方法来禁用重新配置。
创建并返回将新创建的线程设置为已知状态的线程工厂的方法。
从其他类似关闭的表单创建和返回可调用的方法,因此可用于需要执行方法。

Executors类中的方法

查看API发现没有显式的定义构造方法,其中该类中的方法都为静态方法,这一点跟LockSupport类似;

静态方法------>返回值为Callable的

static Callable callable​(Runnable task)

static Callable callable​(Runnable task)
返回可调用对象,当调用时,该对象运行给定任务并返回 null
返回值为Callable,但是返回值为null;

import java.util.concurrent.*;

public class FutureTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Object> th = Executors.callable(new Runnable() {
            @Override
            public void run() {
                System.out.println("我不带结果");
            }
        });
        FutureTask ft = new FutureTask(th);
        Thread thread = new Thread(ft);
        thread.start();

        if (null == ft.get()) {
            System.out.println("真的不带结果");

        }
    }
}

分析------->>>
在这里插入图片描述

static Callable callable​(Runnable task, T result)

static Callable callable​(Runnable task, T result)
返回可调用对象(当调用时)运行给定任务并返回给定结果。当应用需要对其他无结果的行动进行方法时,这很有用。
跟上面类似,只不过带了返回值

package com.gavin;

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

public class ThreadPoolDemo {

    public static void main(String[] args) throws Exception {
        String result="结束";
        Callable<Object> callable = Executors.callable(() -> {
            System.out.println("执行完毕");
        },result);
        Object call = callable.call();
        System.out.println(call);//结束

    }
}

static Callable callable​(PrivilegedAction<?> action)
返回可调用对象(当调用时)运行给定特权操作并返回其结果。

   //callable​(PrivilegedAction<?> action)
        PrivilegedAction p = new PrivilegedAction() {
            @Override
            public Object run() {
                //定义权限条件
                return "需要满足权限条件来触发一些特权";
            }
        };
        Callable<Object> ca = Executors.callable(p);
        FutureTask futureTask = new FutureTask(ca);
        Thread thread1 = new Thread(futureTask);
        thread1.start();
        Object o = futureTask.get();
        System.out.println(o);

在这里插入图片描述

static Callable callable​(PrivilegedExceptionAction<?> action)

static Callable callable​(PrivilegedExceptionAction<?> action)
返回可调用对象(当调用时**)运行给定特权异常操作**并返回其结果。

  PrivilegedExceptionAction pp = new PrivilegedExceptionAction() {
            @Override
            public Object run() throws Exception {

                return "特权异常怎么处理";
            }
        };//可以用Lambada
        Callable<Object> cal = Executors.callable(pp);
        FutureTask<Object> objectFutureTask = new FutureTask<>(cal);
        new Thread(objectFutureTask).start();
        System.out.println(objectFutureTask.get());

在这里插入图片描述

静态方法------------>>>>返回值为ThreadFactory

static ThreadFactory defaultThreadFactory()

static ThreadFactory defaultThreadFactory()
返回用于创建新线程的默认线程工厂。

    //线程工厂用于创建新线程,该线程非守护线程优先级也是线程组中允许的较小和最大优先级.默认为Default
        //新线程的名称可通过线程.getName()的池-N线程-M(N)访问,其中N是本工厂的序列号,M是该工厂创建的线程的序列号。
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        Thread thread2 = threadFactory.newThread(() -> {
            System.out.println("开第一个新线程");
        });
        Thread thread3 = threadFactory.newThread(() -> {
            System.out.println("开第二个新线程");
        });
        thread2.start();
        thread3.start();
        System.out.println(thread2.getName());//pool-1-thread-1
        System.out.println(thread3.getName());//pool-1-thread-2

分析------------>>>>
在这里插入图片描述

静态方法------------>>>>返回值为ExecutorService

static ExecutorService newCachedThreadPool()

static ExecutorService newCachedThreadPool()
创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。

创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。这些池通常会提高执行许多短寿命异步任务的程序的性能。如果可用,将重复使用以前构建的线程。如果没有可用的线程,将**创建一个新的线程并添加到池中。未使用 60 秒的线程被终止并从缓存中删除。**因此,闲置足够长的时间池不会消耗任何资源。请注意,具有类似属性但具有不同详细信息(例如超时参数)的池可能使用线程池执行器构造器创建。execute

  // 创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。
        ExecutorService service = Executors.newCachedThreadPool();
        Thread thread4 = new Thread(() -> {
            System.out.println("我是一个线程");
        });
        FutureTask F= new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {
                System.out.println("我也是一个线程");
                return null;
            }
        });
        service.submit(F);
        service.submit(thread4);
        System.out.println(thread4.getName());
        service.shutdown();

之前在这里遇到过问题,所以也需要分析一下

分析------------>>>
在这里插入图片描述

static ExecutorService newCachedThreadPool​(ThreadFactory threadFactory)

static ExecutorService newCachedThreadPool​(ThreadFactory threadFactory)
创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程,并在需要时使用提供的线程工厂创建新线程。

简言之就是传入一个线程工厂并缓存起来

     ExecutorService service1 = Executors.newCachedThreadPool(threadFactory);
        Thread thread5 = threadFactory.newThread(() -> {
            System.out.println("由线程工厂创建的线程缓冲池中的线程");
        });
        Thread thread6 = threadFactory.newThread(() -> {
            System.out.println("由线程工厂创建的线程缓冲池中的线程");
        });
        service1.submit(thread5);
        service1.submit(thread6);
        System.out.println(thread5.getName());//pool-1-thread-3
        System.out.println(thread6.getName());// pool-1-thread-4
        service1.shutdown();
        

newCachedThreadPool​的缺点

要了解它的缺点,就要看一下源码—>>

线程池的大小有一个范围 0,到Integer.MAX_VALUE,基本算是无界线程池了;然后他的阻塞队列用的是
在这里插入图片描述
1.直接向 SynchronousQueue 中提交任务

2.如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个

3.执行完任务的线程有 60 秒生存时间,如果在这个时间内可以接到新任务,就可以继续活下去,否则就拜拜,由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。CachedThreadPool 用于并发执行大量短期的小任务,或者是负载较轻的服务器。

static ExecutorService newFixedThreadPool​(int nThreads)

static ExecutorService newFixedThreadPool​(int nThreads)

创建一个nThreads大小的线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程。在任何时候,大多数线程都将是主动处理任务。如果在所有线程处于活动状态时提交其他任务,则它们将在队列中等待,直到有线程可用。如果任何线程在关闭前执行**过程中因故障而终止,则如果执行后续任务需要,则将取代新线程。**池中的线程将存在,直到它被明确关闭。

简言之就是我这有一个池子,能容纳 nThreads个线程,当池子满了的时候先添加的线程进入等待,直到池子有空位置的时候,如果池子中的线程再关闭时因为故障而终止,新线程就会取而代之,除非仍然需要这个线程干活,这个线程才会留在池子里,直到它明确关闭

/*   创建一个nThreads大小的线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程。
        在任何时候,大多数线程都将是主动处理任务。如果在所有线程处于活动状态时提交其他任务,
        则它们将在队列中等待,直到有线程可用。如果任何线程在关闭前执行过程中因故障而终止,
        则如果执行后续任务需要,则将取代新线程。池中的线程将存在,直到它被明确关闭。*/
        ExecutorService service2 = Executors.newFixedThreadPool(1);
        Thread  thread7;
        Thread  thread8;
        thread7 = new Thread(() -> {
            for (int i = 10; i < 20; i++) {
            }
            System.out.println("我还留在线程池里吗?");
        });
        thread8 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
            }
            System.out.println("我被执行了吗?");
        });
        service2.submit(thread7);
        service2.submit(thread8);
        service2.shutdown();
static ExecutorService newFixedThreadPool​(int nThreads, ThreadFactory threadFactory)

static ExecutorService newFixedThreadPool​(int nThreads, ThreadFactory threadFactory)
创建一个线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程,使用提供的线程工厂在需要时创建新线程

在这里插入图片描述

static ExecutorService newFixedThreadPool​(int nThreads, ThreadFactory threadFactory)

static ExecutorService newFixedThreadPool​(int nThreads, ThreadFactory threadFactory)
创建一个线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程,使用提供的线程工厂在需要时创建新线程。

跟上面类似,这次是用自己指定的线程工厂创建线程
在这里插入图片描述
newFixedThreadPool​的缺点—>>

静态方法------------>>>>返回值为ExecutorService

static ScheduledExecutorService newScheduledThreadPool​(int corePoolSize)

static ScheduledExecutorService newScheduledThreadPool​(int corePoolSize)
创建一个线程池,可以安排命令在给定延迟后运行,或定期执行。
corePoolSize- 要保留在池中的线程数,即使它们处于空闲状态

 /* 可安排命令在给定延迟后运行或定期执行的执行者服务。
 这些方法会产生各种延迟的任务,并返回可用于取消或检查执行的任务对象。
 并且方法创建和执行定期运行直到取消的任务。schedulescheduleAtFixedRatescheduleWithFixedDelay
使用执行器.执行(可运行)和执行器服务方法提交的命令的延迟为零。
方法中还**允许零延迟和负延迟(但不允许延迟)**,并视为立即执行请求。*/
      ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        //可以传Runnable
        ScheduledFuture<?> ai = scheduledExecutorService.schedule(() -> System.out.println("I love you"), 5, TimeUnit.SECONDS);//延迟为0或者负值则视为不延迟

        //还可以传Callable
        ScheduledFuture<String> schedule = scheduledExecutorService.schedule(() -> "我爱你中国", 2, TimeUnit.SECONDS);
        System.out.println("定时任务的返回值"+schedule.get());

        //除了执行一次性任务外,还可以执行多次任务
        Runnable runnable=()->{
            System.out.println("I LOVE YOU BABY");
        };
        //参数 ,要执行的线程,第一次执行延期的时间,连续执行之间的时间
        ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS);//初始执行延迟10秒,之后每隔一秒打印一句I LOVE YOU BABY

        //scheduledExecutorService.shutdown();

        System.out.println("------------------------Executors.newScheduledThreadPool(2, threadFactory1);----------------------------");
        ScheduledExecutorService scheduledExecutorService1 = Executors.newScheduledThreadPool(2, threadFactory1);
        Thread thread11 = threadFactory1.newThread(() -> {
            System.out.println("五秒后提醒我玩游戏");
        });
        scheduledExecutorService1.schedule(thread11, 6, TimeUnit.SECONDS);
        scheduledExecutorService1.shutdown();

简单研究一下scheduleAtFixedRate与scheduleWithFixedDelay

scheduleAtFixedRate

分为两种情况------------>>>>>>>>>>>>
第一种是如果任务执行的时间小于等于周期即设置的参数----period 那么就会按照周期设定值进行循环任务执行

//导包.....略
public class TestSchedule {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        Runnable runnable=()->{
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I LOVE YOU BABY");
        };
        scheduledExecutorService.scheduleAtFixedRate(runnable,1,1, TimeUnit.SECONDS);
    }
}

//假设初始时间为0
//任务第一次执行 延迟1秒
//从开始到第一次执行时间 要延迟1秒,在到第一次执行完,总共花了initialDelay(初始延迟1秒)+ 执行时间(忽略不计,反正不超过1秒),执行时间不超过Period,下一个任务在上一个执行完毕之后1秒后开始执行,即各任务之间并不是并发任务
//第二次执行的时间为initialDelay(1秒)+ 第一次执行时间(忽略不计)=第2秒 开始, 第二次执行完后1秒又开始执行第三次

第二种是如果任务时间大于周期即设置的参数----period ,那么就会在等待上一个任务完成后立即执行下一个任务


public class TestSchedule {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        Runnable runnable=()->{
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I LOVE YOU BABY");
        };
        scheduledExecutorService.scheduleAtFixedRate(runnable,1,1, TimeUnit.SECONDS);
    }
}

//依旧假设初始时间为0
//任务第一次执行延迟1秒,每隔1秒执行一次,但是一次任务需要5秒,
//开始到第一次执行时间延迟1秒,到第一次执行完 总共花了initialDelay(1秒)+ 执行时间(5秒),然 超过Period了,下一个线程等待等上一个线程结束后才开始立即执行, 即并不是并发任务
//第二次执行的时间为initialDelay(1秒)+ 第一次执行时间(5秒)=第六秒 开始,然后执行一次又花了5秒, 第二次执行完的时间 为第11秒

scheduleWithFixedDelay

也是分为两种情况讨论--------->>>>>>>
第一种任务执行时间小于等于延迟时间

public class TestSchedule {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
             Runnable runnable2=()->{
            System.out.println("我爱你宝贝");
        };
scheduledExecutorService.scheduleWithFixedDelay(runnable2,1,3,TimeUnit.SECONDS);
    }
}

//依旧假设初始时间为0;
从开始到第一个任务执行 延迟1秒 第一秒
第一个任务开始到第一个任务结束 花费时间忽略不计
从第一个任务结束到第二个任务开始 花费 3秒 即第二个任务在第四秒时开始;

第二种情况是当任务执行时间大于延迟时间


public class TestSchedule {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        Runnable runnable2=()->{
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我爱你宝贝");
        };
scheduledExecutorService.scheduleWithFixedDelay(runnable2,1,3,TimeUnit.SECONDS);
    }
}

依旧假设初始时间为0 第一次执行时 延迟 1秒, 第1秒
由于任务执行时间为5秒, 所以第一次执行时间结束为 第6秒,
等着第一次任务执行结束后 在延迟 3秒执行下一次任务, 第9秒
即每次任务结束到下一次任务开始之间间隔为 3秒 所以第二次执行开始的时间为 第 9秒,结束时间 第14秒,在等待三秒下一次任务才开始执行;

看一下源码吧!!!
在这里插入图片描述
在这里插入图片描述

ThreadPoolExecutor

public class ThreadPoolExecutor
extends AbstractExecutorService

案例代码—>>

package com.gavin;

import java.util.ArrayList;
import java.util.concurrent.*;

public class ThreadPoolDemo {
    public static void main(String[] args) {
       /* new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return null;
            }
        };*/
        RejectedExecutionHandler rejectedExecutionHandler = (r, executor) -> {
            if (executor.getTaskCount() >= 6) {
                System.out.println("程序被终止");
                System.exit(1);
            }

        };
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(1);
        //核心线程 2,最大线程数4 核心线程可超时2秒 ,超出最大线程进入阻塞队列 (可调阻塞队列大小)
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1, TimeUnit.SECONDS, blockingQueue,new ThreadPoolExecutor.CallerRunsPolicy());

        ArrayList<Runnable> arrayList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            arrayList.add(() -> {
                System.out.println("hello-world"+ finalI);
            });
        }
        for (int i = 0; i < 10; i++) {
            threadPoolExecutor.execute(arrayList.get(i));
        }
    }
}

在这里插入图片描述
核心和最大池大小
将根据corePoolSize和 maximumPoolSize设置的边界自动调整池大小,在提交新任务时,如果运行的线程小于核心线程数,则会创建一个新线程来处理请求,其他线程处于空闲状态也是要创建新线程的,如果运行的线程数小于最大值,也将创建一个新线程来处理

任何 BlockingQueue 都可用于传输和保留已提交的任务。此队列的使用与池大小调整交互:
如果运行的线程少于 corePoolSize 线程,则执行程序始终倾向于添加新线程而不是排队。
如果 corePoolSize 或更多线程正在运行,则执行程序始终倾向于对请求进行排队,而不是添加新线程。
如果请求无法排队,则会创建一个新线程,除非该线程超过 maxPoolSize,在这种情况下,任务将被拒绝。,

newSingleThreadExecutor

FinalizableDelegatedExecutorService–可中止的委托线程执行服务

 public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newSingleThreadScheduledExecutor

提交一个定期操作,该操作在给定的初始延迟后首先启用,随后在给定的时间段内启用;也就是说,处决将在 之后开始,然后 ,然后,依此类推。initialDelayinitialDelay + periodinitialDelay + 2 * period
任务执行的顺序无限期地继续,直到发生以下异常完成之一:

该任务通过返回的未来显式取消。
执行程序终止,也会导致任务取消。
执行任务会引发异常。在这种情况下,在返回的未来调用 get 将抛出 ExecutionException,将异常作为其原因。
后续执行将被抑制。在返回的未来对 isDone() 的后续调用将返回 。true
如果执行此任务所需的时间超过其周期,则后续执行可能会延迟开始,但不会同时执行。

  public static void Demo4(){
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(()->System.out.println("nihao"),10,10,TimeUnit.SECONDS);
//    scheduledExecutorService.shutdown();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeMartain

祝:生活蒸蒸日上!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值