如下三种业务,应该如何使用线程池:
1.高并发,任务执行时间短的业务
2.并发不高,任务执行时间长的业务
3.并发高,业务执行时间长的业务
回答:1.高并发,任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文切换
2.并发不高,任务执行长,需要区分:(1)业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有CPU空闲下来,可以加大线程池中的数目,让CPU处理更多的业务。
(2)业务时间长集中在计算操作上,就是计算密集型任务,这个就没办法了,可以把线程池中的线程数设置的少一些,减少线程上下文的切换。
3.并发高,业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,可以参考2。最后,业务执行时间长问题,也需要分析看能不能使用中间件对任务进行拆分和解耦。
问:线程池shutdown和shutdownnow的区别,实现原理
答:shutdown(),当线程池调用该方法时,线程池的状态则立刻变成shutdown状态。此时,则不能再往线程池中添加任何任务,否则将抛出rejectedExecutionException异常。但是此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
shutdownnow(),大致意思是,执行该方法,线程池的状态立刻变成stop状态,并试图停止所有正在执行的线程,不在处理还在池队列中等待的任务,当然,会返回那些未执行的任务。它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家都知道,这种方法的作用有限,如果线程池中没有sleep,wait,condition,定时锁等应用,interrupt()方法是无法中断当前的线程的。所以shutdown()并不代表线程池就一定会立即退出,它可能必须要等待所有正在执行的任务都执行完了才能退出。
java并发类库提供的线程池有哪几种,分别有什么特点,在使用时需要注意什么。
通常开发者都是利用executors提供的通用线程池创建方法,去创建不同配置的线程池。主要区别在于不同的executors目前提供了5种不同的线程池创建配置:
1.newCachedThreadPool(),它是一种用来处理大量短时间工作任务的线程池。具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SychronousQueue作为工作队列。
2.newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目nThreads。
3.newSingleThreadExecutor(),它的特点在于工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目。
4.newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),创建的是个ScheduledThreadPoolExecutor,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
5.newWorkStealingPool(int parallelism),这是一个经常被人忽略的线程池,Java 8才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序。
项目中有高并发吗,怎么解决,回答:
解决思路从几点出发:1.代码层面,锁优化措施,尽量简化事务和减少事务2.应用层面:缓存,队列,限流,熔断,负载均衡等3.数据库层面:分库分表,读写分离。4.还有一些比如代码中常用到的并发包处理工具中,ConcurrentHashMap,CopyOnWriteArrayList,CopyOnWriteArraySet等。
ThreadLocal
经常会有人一直把threadLocal和ThreadPool搞混,这里重点申明下,ThreadPool是线程池,完全不是一回事哦,线程池干嘛的,可以把它当做是容纳线程的容器,线程池是为突然大量暴增的线程设计的,通过有限的几个固定或者缓存量等线程为大量的线程提供操作服务,减少了创建和销毁所需的时间,提高效率。
threadLocal是什么,从名字看叫做线程变量,意思是threadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,threadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
2.ThreadLocal怎么用
既然ThreadLocal的作用是每一个线程创建一个副本,我们使用一个例子来验证一下:
public class one {
public static void main(String[] args) {
ThreadLocal<String> local=new ThreadLocal<>();
Random random=new Random();
//java8的stream
IntStream.range(0,5).forEach(a-> new Thread(()->{
//为每一个线程设置相应的local值
local.set(a+" "+random.nextInt(10));
System.out.println("线程和local值分别是:"+local.get());
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}).start());
}
}