自定义的线程或者newFixedThreadPool()使用 LinkedBlockingQueue 作为任务队列的需要注意
案列 1:
有两处业务 共用了一把锁
lock.writeLock().lock();
try{
while(true){
//clean data
}
}finally{
lock.writeLock().lock();
}
从这里看出,因为长时间持有 lock,那么其它线程肯定会阻塞。
lock.readLock.lock();
try{
// check
}finally{
lock.readLock.unlock();
}
请求来的时候,这里会 check 一些参数,这个地方会拿 lock,这么看
清理逻辑,会阻塞住请求过来的业务
发送端出现了超时的问题
所有为什么发送方会出现了超时。
找到线程池,发现所有的请求都会经过一个线程池。疑问:线程池满了,业务方占用了线程池,于是导致发送方请求处理 不了,超时,这时候就要去找日志,看是否有 RejectedException().发现没有日志。
查看线程池的实现,
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
LinkedBlockingQueue 知道 队列大小 Integer.MAX_VALUE,导致请求都会阻塞到 queue 里面了
综上问题:
锁的粒度过大,长时间占用锁。
所有业务都用同一个线程池,应该分成多个业务线程池,关键业务分开。防止所有任务都被阻塞
在这 记录下 曾经遇到的 对 ThreadPoolExecutor 的 不正当使用 导致死锁的问题
案列 2:
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(2,100,2L,TimeUnit.MINUTES,new LinkedBlockingQueue<>(),new ThreadFactory(){
private AtomicInteger id = new AtomicInteger(0);
@Override
public Thread newThread(Runable r){
Thread thread = new Thread();
thread.setName(“core_service”+id.addAndGet(1));
return thread;
}
},new ThreadPoolExecutor.CallerRunPolicy());
public static void main(String[] args)throws Exception{
Future<Long> f1 = (Future<Long>) executor.submit(()->{
Thread.sleep(1000);
Future<Long> f3 = (Future<Long>) executor.submit(()->return -1L);
System.out.println(“f1,f3″+f3.get());
return -1L;
});
Future<Long> f2 = (Future<Long>) executor.submit(()->{
Thread.sleep(1000);
Future<Long> f4 = (Future<Long>) executor.submit(()->return -1L);
System.out.println(“f2,f4″+f4.get());
return -1L;
});
System.out.println(“here”);
System.out.println(“f1″+f1.get());
System.out.println(“f2″+f2.get());
}
结果 :here
线程阻塞了,无法得到 f1,f2
原因:当使用 LinkedBlockingQueue 不指定大小的话,maxmumPoolsize 此配置将无效。因为当线程数量达到 coreSize 时,会放入队列等待,队列是无界的,导致线程数量达到 core 就不会增长。
so:线程执行 f1 占用一个线程,延迟到 f2 也占用一个线程,此时 执行 f3 提交到队列中执行,一直等待执行没有返回,导致 f2 完成不了,导致了问题的发生。