
编程
文章平均质量分 66
藤原佐为.
这个作者很懒,什么都没留下…
展开
-
pool(一)——入门
线程池的用法和这个不太一样,因为线程的run方法执行完之后,一个线程的使命就结束了。所以如果要想重用线程,就需要阻止run方法的结束,用死循环等方法。目前jdk线程池使用的是结合LinkedBlockingQueue,通过队列的阻塞方法让当前线程休眠,等待任务并处理,实现单个线程的重用。取任务的时候,如果allowCoreThreadTimeOut是true,或者当前线程数量已经超过了核心线程数量,从LinkedBlockingQueue中取任务会有等待时间,等待的时间由keepAliveTime决定。..原创 2022-07-22 17:57:34 · 153 阅读 · 0 评论 -
pool(二)——动手入门
保证{@linkGenericObjectPool#idleObjects}对象的size和{@linkGenericObjectPool#getMinIdle}一致。但是如果{@linkGenericObjectPool#createCount}=={@linkGenericObjectPool#maxTotal}池化对象工程,这里的池化对象是MyConnection,这个工厂就是负责产生MyConnection对象的,产生的对象会放到池子中。4.对象池中对象数量控制。......原创 2022-07-22 17:58:06 · 132 阅读 · 0 评论 -
pool(三)——Timer
第三个入队列,index是3,3>>1=1,和第一个比,queue[3]比queue[1]要早,所以交换顺序,所以现在queue[1]最早执行,queue[2]和queue[3]的顺序没有考虑。这里以3个为例,第一个入队列,index是1,第二个入队列,index是2,2>>1=1,然后拿queue[2]和queue[1]比较下次执行时间,queue[2]比queue[1]早,所以交换顺序。所以,当本次任务执行结束(过了超过5s),到下次任务取出来判断的执行时间的时候,肯定已经超过了原本应该执行的时间。..原创 2022-07-22 17:58:39 · 115 阅读 · 0 评论 -
pool(四)——EvictionTimer
但是如果{@linkGenericObjectPool#createCount}=={@linkGenericObjectPool#maxTotal},{@linkGenericObjectPool#create}方法就无法继续创建对象了。该类是TimerTask的子类,run方法有两个主要功能,evict和ensureMinIdle,一个是清除对象池中过期的对象,一个是保证对象池中始终有个数为minIdle个对象。该方法中使用了EvictionPolicy来判断是对象池中的对象是否过期了。......原创 2022-07-22 17:59:12 · 288 阅读 · 0 评论 -
pool(五)——BasicDataSource
也是从_pool这个变量中调用borrowObject拿对象,这个_pool对象就是上面说的GenericObjectPool,所以最终还是调用GenericObjectPool的borrowObject方法拿对象。可以把PoolingDataSource看作GenericObjectPool的包装,BasicDataSource的getConnection最终还是从GenericObjectPool中拿对象。query真正执行的时候,才会去获取连接。1.一次query流程。......原创 2022-07-22 17:59:43 · 355 阅读 · 0 评论 -
pool(六)——JedisPool
和上一篇数据库连接池的PoolingDataSource一样,这个Pool类包装了对象池,里面存放了一个GenericObjectPool类型的internalPool变量。本文剖析redis.clients.jedis中关于jedis连接池部分的源码。因为只涉及连接池的部分思想,不设计具体jedis底层创建连接部分,所以篇幅很小。和jedis的创建销毁相关的工厂类。...原创 2022-07-22 18:00:21 · 136 阅读 · 0 评论 -
ThreadPoolExecutor(一)——简介
一个ThreadPoolExecutor从初始化到执行需要经历如下几个环节。ThreadPoolExecutor初始化。原创 2022-07-22 18:02:12 · 180 阅读 · 0 评论 -
ThreadPoolExecutor(二)——execute
3.如果任务无法入队列,再次尝试addWorker,这次是用正在run的线程数和maximumPoolSize比,如果超过了maximumPoolSize则reject任务,说明线程池已经饱和了。2.如果addWorker方法执行失败了,任务要入队列,如果成功入队列了,需要做doublecheck来处理一些极端情况,比如线程池是否shutdown了等等。这个代码块,首先加锁,整个类用到这个锁的地方,除了获取该线程池的一些关键参数之外,就是shutdown和terminate等相关操作。...原创 2022-07-22 18:02:42 · 639 阅读 · 0 评论 -
ThreadPoolExecutor(三)——Worker
我们可以在beforeExecute方法中抛出异常,这样task不会被执行,而且在跳出该循环的时候completedAbruptly的值是true,表示theworkerdiedduetouserexception,会用decrementWorkerCount调整wc。上面说过,addWorker会用当前task创建一个Worker对象,相当于对task的包装,然后用Worker对象作为task创建一个Thread,该Thread保存在Worker的thread成员变量中。...原创 2022-07-22 18:03:15 · 413 阅读 · 0 评论 -
ThreadPoolExecutor(四)——Interrupt
Thread.interrupted()方法判断的时候返回了true,同时擦除了中断标志位,所以再用Thread.currentThread().isInterrupted()判断的时候,就返回false了。Thread的成员函数isInterrupted判断标志位的时候不会清除标志位,如果返回true,那么无论执行多少次都会返回true(期间没有其他清除标志位的操作的话)。interrupt对于正常运行的线程起不到中断作用,只是把该线程的中断标志位设置为true了,线程会继续正常运行。...原创 2022-07-22 18:03:45 · 642 阅读 · 0 评论 -
ThreadPoolExecutor(五)——线程池关闭相关操作
补充了和Thread的interrupt操作相关的知识,回头再来看ThreadPoolExecutor中interrupt,关闭线程池等相关操作。先看注释:开始一个顺序的shutdown操作,shutdown之前被执行的已提交任务,新的任务不会再被接收了。如果线程池已经被shutdown了,该方法的调用没有其他任何效果了。该方法不会等待之前已经提交的任务执行完毕,awaitTermination方法才有这个效果。具体看内部逻辑,checkShutdownAccess这个方法是确保允许调用发interr原创 2022-07-22 18:04:23 · 2467 阅读 · 0 评论 -
ThreadPoolExecutor(六)——线程池关闭之后
上一篇主要从代码角度介绍了线程池关闭相关的方法,包括各个方法之间的逻辑关系,调用关系和产生的效果。这一篇更多从逻辑角度上来说一下线程池在shutdown之后,原来正常的处理流程有哪些变化,既是总结也是扩展。shutdown操作之后,首先最重要的一点变化就是线程池状态变成了SHUTDOWN。该状态是开始关闭线程池之后,从RUNNING改变状态经过的第一个状态(还有一种情况是直接进STOP,调用shutdownNow的时候),有个图画的挺好,见博客。...原创 2022-07-22 18:04:55 · 2201 阅读 · 0 评论 -
ThreadPoolExecutor(七)——总结&补充
线程池的submit方法提交的任务是一个FutureTask,它既含有Runnable的任务属性也含有Future的属性。在设置异常之后,用future的get(内部是Sync的innerGet方法)方法获取结果的时候会抛出异常,线程池在执行execute方法和submit任务的时候,如果任务中抛出了异常,外部线程无法感知,所以要做一些措施来进行处理,下面就说一下产生这种效果的原因以及一些可用的处理方法。在构造线程池的时候,作为参数传递我们自己封装的线程工厂。,同时记录日志和监控。自己封装线程的工厂类。..原创 2022-07-23 00:09:06 · 225 阅读 · 0 评论 -
log(一)——MDC入门
MDC中包装了一个MDCAdapter,这是一个接口,不同的log包有自己对应的实现。对于不支持MDC的包,比如java.util.logging,使用默认的BasicMDCAdapter,slf4j-nop有NOPMDCAdapter。简单来说就是日志的增强功能,如果配置了MDC,并添加了相应的keyvalue,就会在打日志的时候把key对应的value打印出来。内部是用ThreadLocal来实现的,可以携带当前线程的context信息。这是MDC类上的注释,但是没有讲这个是干什么的。......原创 2022-07-23 00:09:21 · 975 阅读 · 0 评论 -
log(二)——MDC实现之ThreadLocal
在Thread的init方法中,是通过获得当前线程作为parent线程,也就是说,在哪个线程中new的这个Thread并start的,执行该操作的线程就是new的新Thread的parent线程。threadLocals保存的是当前线程中的ThreadLocal变量们,inheritableThreadLocals保存的是当前线程父线程中的变量们。但是init方法只在线程初始化的时候执行一次,所以如果用的线程池来使线程重用的话,就不会再调用这个init方法了,这会带来一些问题,后面会具体说。......原创 2022-07-23 00:09:31 · 703 阅读 · 0 评论 -
log(三)——MDCAdapter之实现LogbackMDCAdapter
然后这个方法中的同步块也很奇怪,为什么父线程会能修改这个map,其他线程能修改这个map的地方只有通过getPropertyMap方法来获得copyOnInheritThreadLocal内容的引用,然后修改这个map的内容,只有这一处,但是一般使用MDC应该不会用getPropertyMap方法获取内容然后进行操作吧,不知道为什么把这个方法公有化,而不是包一个ImmutableMap再对外暴露。这里觉得copyonwrite依然浪费性能,所以只在get操作后做copyonwrite。......原创 2022-07-23 00:09:44 · 856 阅读 · 0 评论 -
log(四)——MDC使用
之前说过,子线程在创建的时候会把父线程中的inheritableThreadLocals变量设置到子线程的inheritableThreadLocals中,而MDC内部是用InheritableThreadLocal实现的,所以自然会把父线程中的上下文带到子线程中。对于线程池中的线程来说,这部分线程是可以重用的,但是线程本身只会初始化一次,所以之后重用线程的时候,就不会进行初始化操作了,也就不会有上一段中提到的父线程inheritableThreadLocals拷贝到子线程中的过程了。......原创 2022-07-23 00:09:55 · 1994 阅读 · 0 评论 -
log(五)——MDC总结
但是如果用ThreadPool线程池的话,线程是可以重用的,如果之前的线程的MDC内容没有清除掉的话,再次重线程池中获取到这个线程,会取出之前的数据(脏数据),会导致一些不可预期的错误,所以当前线程结束后一定要清掉。所以MDC类的静态变量mdcAdapter(LogbackMDCAdapter实现)中的copyOnInheritThreadLocal会得到父类MDC写入的内容,因为它用的是。答如果都是用newThread方法建立的线程没有问题,因为之后线程会消亡。......原创 2022-07-23 00:10:09 · 1522 阅读 · 0 评论 -
ThreadPoolExecutor(八)——ScheduledThreadPoolExecutor
所以我们看到,我们大部分场景都不需要有纳秒级别的精确度,所以使用HashedWheelTimer可以让我们的处理速度更快,将超时时间不同但相差不大的多个任务在同一个tick内得到处理。因此,我倾向于使用硬件定时器来处理这种用例,因为您必须以最小的开销快速地安排任务,即O(1)用于新任务。来源(+wheel定时器常规文档),以下是基本差异(N-迄今为止所有未完成预定任务的数量,C轮大小)的ScheduledThreadPoolExecutor。...原创 2022-07-25 18:16:57 · 261 阅读 · 0 评论 -
ThreadPoolExecutor(九)——ScheduledThreadPoolExecutor和HashedWheelTimer比较
所以我们看到,我们大部分场景都不需要有纳秒级别的精确度,所以使用HashedWheelTimer可以让我们的处理速度更快,将超时时间不同但相差不大的多个任务在同一个tick内得到处理。因此,我倾向于使用硬件定时器来处理这种用例,因为您必须以最小的开销快速地安排任务,即O(1)用于新任务。来源(+ wheel定时器常规文档),以下是基本差异(N - 迄今为止所有未完成预定任务的数量,C轮大小): 的ScheduledThreadPoolExecutor。原创 2023-06-09 18:21:24 · 304 阅读 · 0 评论