java中的线程池-学习之路(2)

    技术2022-07-10  101

    一、Callable和Future接口

    ​ 1.介绍

    ​ Callable和Runnable都封装一个异步运行的任务:

    ​ Runnable:可以看成一个无参,无返回值的接口

    ​ Callable:有返回值的接口,里面有一个call()方法

    ​ Future :用来保存异步计算的结果,启动一个计算,将Future对象交给这个线程,忘掉它,Furture对象的所用者将会在得出结果后就可以得到这个值

    2.FutureTask包装器:可以将Callable转换成Runnable,同时实现了这二中接口。

    Callable<String> call=new Callable(); FutureTask<String >tack=new Future<String>(call); //将Callable转换成Runnable Thread th=new Thread(tack); //创建线程 th.start(); //开启线程 String try=tack.get() //执行任务,调用阻塞,直到结束
    2.1 执行器 Executor
    为什么使用过线程池 1.构建一个新的线程是有一定代价的,因为沙及与操作系统的交互, 如果程序中创建了大量的生命期很短的线程,应该使用线程池(thread pool)。 一个线程池中包含许多准备运行的空闲线程。将Runnable对象交给线程池,就会有一个线程调用run方法。 当run方法退出时,线程不会死亡,而是在池中准备为下一个请求提供服务。 2.另一个使用线程池的理由是减少并发线程的数目。 创建大量线程会大大降低性能其至使虚拟机崩溃。 如果有一个会创建许多线程的算法,应该使用一个线程数“固定的“线程池以限制并发线程的总数。
    Executor接口介绍 1.一种执行器,提供管理终止的方法和可以产生Future用于跟踪一个或多个异步任务进度的方法。 2.接口方法 execute(Runnable command); //执行任务,无返回值 3.ExecutorServic 继承 Executor
    2.2.Executors的静态工厂
    1.new CacheThreadPool //必要时创建新线程,空闲是线程保留60秒 2.new FixedThreadPoll //包含固定的线程数量,线程会被一直保留 3.new SigneThreadExecutor //线程池中只有一个线程,会顺序的执行每一个提交的任务 4.new ScheduledThreadPool //预定执行的固定线程池,可以理解为定时发送任务。 5.new SingleThreadScheduledExecutor //单线程池

    2.3 线程池
    1.new CacheThreadPool //必要时创建新线程,空闲是线程保留60秒 2.new FixedThreadPoll //包含固定的线程数量,线程会被一直保留 3.new SigneThreadExecutor //线程池中只有一个线程,会顺序的执行每一个提交的任务 /** 这三和方法返回实现了ExecutorService接口的ThreadPollExcuteor类的对象 用下面三个方法来将Runnable或者Callable对象提交给ExecutorService,返回一个Future对象来查询任务的状态。 1.Future<?> submit(Runnable tack) get() 任务完成返回null 2.Future<T> submit(Callable<T> tack) Furture对象的所用者将会在得出结果后就可以得到这个值。 3.Future<T> submit(Runnable tack,T result) 使用get()方法是 任务完成返回指定的result对象 */

    2.3线程池的参数

    ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } corePoolSize:核心线程数量 maximumPoolSize:最大线程数量; workQueue:等待队列,当任务提交时,如果线程池中的线程数量大于等于corePoolSize的时候,把该任务封装成一个Worker对象放入等待队列; keepAliveTime:线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime; TimeUnit :时间级别 threadFactory:它是ThreadFactory类型的变量,用来创建新线程。 handler:它是RejectedExecutionHandler类型的变量,表示线程池的饱和策略。如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务。 ThreadFactory:定义线程池中创建的线程,如线程名称,优先级等,可以几次ThreadFactory重新newThread(Runnable r)方法。

    2.4线程池执行的基本流程

    当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
    2.5使用线程的大体步骤
    调用Executors类的静态方法 例如 new CacheThreadPool对象调用submit 提交Runnable或者Callable,用execute无返回值。想取消任务,或者要提交Callable是要保存好返回的Future对象不在想提交任务时,关闭将线程对象返回线程池用shutdown或者shutdownNew关闭所有; package com.basic.test; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class ThreadTest implements Runnable { public static void main(String[] args) throws InterruptedException { //创建一个定长为3的线程池 ExecutorService service = Executors.newFixedThreadPool(3); //提交二个任务 service.submit(new ThreadTest()); service.submit(new ThreadTest()); //关闭线程 service.shutdown(); } //要执行的任务 @Override public void run() { for (int i=0;i<10;i++) System.out.println(Thread.currentThread().getName()+"--->"+i); } } 执行结果部分: pool-1-thread-2--->9 pool-1-thread-1--->3 pool-1-thread-1--->4 pool-1-thread-1--->5 pool-1-thread-1--->6 pool-1-thread-1--->7 pool-1-thread-1--->8 pool-1-thread-1--->9

    参考链接

    [https://www.jianshu.com/p/9beab78a3afe]:

    Processed: 0.033, SQL: 12