ARTS-11(动态规划、线程池解析、Feign原生接口调用、好用工具推荐)

Algorithm

动态规划思路及解题

Review

线程池的使用

1)、多线程的好处

  1. 提升资源利用率
  2. 提高程序处理效率:例如对执行顺序不敏感的任务,可以交由多个线程进行并行处理
  3. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  4. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  5. 线程池作用就是限制系统中执行线程的数量,用线程池控制线程数量,其他线程排 队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池 中有等待的工作线程,就可以开始运行了;否则进入等待队列。

2)、线程池的创建

  1. 实现Runable接口并重写run()方法
  2. 实现Callable接口并重写call()方法
  3. 继承Thread类并重写run()方法
  4. 使用线程池,将任务交付给线程池,由线程池按照指定的方式进行调度,创建线程主要有以下两种方式:
    a、直接创建ThreadPoolExecutor实例
    b、 使用Executors创建常见的线程池类型(不推荐使用)

直接创建ThreadPoolExecutor实例

ThreadPoolExecutor的四种构造函数:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {}

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {}

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

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,
long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler){}

在这里插入图片描述

参数说明:
corePoolSize:核心线程数。在创建线程池之后,默认情况下线程池中并没有任何的线程,而是等待任务到来才创建线程去执行任务,当线程池中的线程数目达到 corePoolSize后,新来的任务将会被添加到缓存队列中,也就是那个workQueue,除非调用ThreadPoolExecutor#prestartAllCoreThreads()方法或者是 ThreadPoolExecutor # prestartCoreThread()方法(从这两个方法的名字就可以看出是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或一个线程)。

maximumPoolSize:允许在线程池中存活的最大线程数量,当线程池中的线程数等于 corePoolSize 并且 workQueue 已满,这时就要看当前线程数是否大于 maximumPoolSize,如果小于maximumPoolSize 定义的值,则会继续创建线程去执行任务, 否则将会调用去相应的任务拒绝策略来拒绝这个任务。另外超过 corePoolSize的线程被称做"Idle Thread", 这部分线程会有一个最大空闲存活时间(keepAliveTime),如果超过这个空闲存活时间还没有任务被分配,则会将这部分线程进行回收。

keepAliveTime:现成的最大空闲时间,当超过这个时间后线程会被终止

unit:keepAliveTime的单位

workQueue:用户保存已被提交尚未被执行的任务

  • ArrayBlockingQueue       //基于数组的先进先出队列,此队列创建时必须指定大小;
  • LinkedBlockingQueue      //基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE
  • synchronousQueue        //这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

threadFactory:线程工厂。用来为线程池创建线程,当我们不指定线程工厂时,线程池内部会调用Executors.defaultThreadFactory()创建默认的线程工厂,其后续创建的线程优先级都是Thread.NORM_PRIORITY。如果我们指定线程工厂,我们可以对产生的线程进行一定的操作。
handler:拒绝执行策略。当线程池的缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略

实际运用

ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,200,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
//public void execute(Runnable command)
executor.execute(task);

private ThreadPoolExecutor jobExecutor = new ThreadPoolExecutor(
            10, 10, 1, TimeUnit.MINUTES,
            new ArrayBlockingQueue<>(1000),
            r -> new Thread(r, "schedule-worker-" + jobWorkerCount.incrementAndGet()),
            (r, executor) -> {
                r.run();
                ScheduleAlarmUtil.alarm("定时任务线程池溢出",
                        r + " \nqueue.size=" + executor.getQueue().size(),
                        "schedule-pool-reject-" + DateFormatUtils.format(new Date(), "yyyyMMdd"));
            });

java通过Executors线程工具类创建线程池

Java通过Executors提供四种线程池,分别为:
1、newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。其工作线程的创建数量几乎没有限制。maximumPoolSize=Integer.MAX_VALUE

2、newFixedThreadPool 创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池对列中。

其任务队列的长度基本是无限的,具有内存溢出的风险new LinkedBlockingQueue()

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

其工作线程的创建数量几乎没有限制(maximumPoolSize=Integer.MAX_VALUE),任务队列长度也是基本是无限的,具有内存溢出的风险

4、newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
其任务队列的长度基本是无限的,具有内存溢出的风险new LinkedBlockingQueue()

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
}


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

实际使用

ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
TaskC task = new TaskC();
ScheduledFuture<String> future = pool.schedule(task,1,TimeUnit.SECONDS);

Tips

原生Feign调用接口的方法

1、maven引入

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-core</artifactId>
    <version>10.1.0</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.netflix.feign</groupId>
    <artifactId>feign-gson</artifactId>
    <version>8.4.1</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.1.0</version>
</dependency>

2、实际使用

public interface xxxClient {
	@RequestLine(value = "GET /xx/xxx/xxx/getxxx?userId={UserId}&currentPage={currentPage}&pageSize={pageSize}")
    @Headers("Authorization:Basic {token}")
    public xxxResponseEntity<xxxPage<String>> getDatabase(@Param("token") String token,@Param("userId") String userId, @Param("currentPage") Integer currentPage, @Param("pageSize") Integer pageSize);

}
public void method{
	private BDPClient getxxxClient(){
	       return Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(xxxClient.class, cdhHost);
	   }

    private String getDefaultToken(){
        return new String(Base64.encodeBase64(cdhToken.getBytes()));
    }

    public xxxResponseEntity<xxxPage<String>> getDatabase(String userId, Integer currentPage, Integer pageSize) {
        return getxxxClient().getDatabase(getDefaultToken(), userId, currentPage, pageSize);
    }
}

Share

分享一些程序员好用工具:
1、截图工具:snipaste,使用简单,贴图方便
2、desktopcal桌面日历是一款桌面工具,通过desktopcal桌面日历,你可以很方便的记录事项、管理日程,让你在每次看到桌面时就能及时知道制定的计划完成度等
待更。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值