Algorithm
Review
线程池的使用
1)、多线程的好处
- 提升资源利用率
- 提高程序处理效率:例如对执行顺序不敏感的任务,可以交由多个线程进行并行处理
- 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
- 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
- 线程池作用就是限制系统中执行线程的数量,用线程池控制线程数量,其他线程排 队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池 中有等待的工作线程,就可以开始运行了;否则进入等待队列。
2)、线程池的创建
- 实现Runable接口并重写run()方法
- 实现Callable接口并重写call()方法
- 继承Thread类并重写run()方法
- 使用线程池,将任务交付给线程池,由线程池按照指定的方式进行调度,创建线程主要有以下两种方式:
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}¤tPage={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桌面日历,你可以很方便的记录事项、管理日程,让你在每次看到桌面时就能及时知道制定的计划完成度等
待更。。。