<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[xocupid的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/xocupid</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; xocupid]]></copyright><item><title><![CDATA[【AI学习】GitHub开源项目直接生成coze skill]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/157610022</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/157610022</guid><author>xocupid</author><pubDate>Sun, 01 Feb 2026 01:23:04 +0800</pubDate><description><![CDATA[摘要：本文分享了在Cozeskill中使用开源项目生成skill的第二种方法。作者以FFmpeg项目为例，首次尝试因提示词过多失败，简化后成功生成可用skill。测试中将视频转为GIF功能有效，但需注意下载方式：需右键下载或从文件夹获取，直接点击会下载为图片格式而非GIF。实验表明该方法可行但存在一定失败率，可能与底层模型能力有关。]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(九)——ScheduledThreadPoolExecutor和HashedWheelTimer比较]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/131132967</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/131132967</guid><author>xocupid</author><pubDate>Fri, 09 Jun 2023 18:21:24 +0800</pubDate><description><![CDATA[所以我们看到，我们大部分场景都不需要有纳秒级别的精确度，所以使用HashedWheelTimer可以让我们的处理速度更快，将超时时间不同但相差不大的多个任务在同一个tick内得到处理。因此，我倾向于使用硬件定时器来处理这种用例，因为您必须以最小的开销快速地安排任务，即O(1)用于新任务。来源(+ wheel定时器常规文档)，以下是基本差异(N - 迄今为止所有未完成预定任务的数量，C轮大小)： 的ScheduledThreadPoolExecutor。]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(八)——ScheduledThreadPoolExecutor]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125980673</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125980673</guid><author>xocupid</author><pubDate>Mon, 25 Jul 2022 18:16:57 +0800</pubDate><description><![CDATA[所以我们看到，我们大部分场景都不需要有纳秒级别的精确度，所以使用HashedWheelTimer可以让我们的处理速度更快，将超时时间不同但相差不大的多个任务在同一个tick内得到处理。因此，我倾向于使用硬件定时器来处理这种用例，因为您必须以最小的开销快速地安排任务，即O(1)用于新任务。来源(+wheel定时器常规文档)，以下是基本差异(N-迄今为止所有未完成预定任务的数量，C轮大小)的ScheduledThreadPoolExecutor。...]]></description><category></category></item><item><title><![CDATA[log(五)——MDC总结]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937743</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937743</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:10:09 +0800</pubDate><description><![CDATA[但是如果用ThreadPool线程池的话，线程是可以重用的，如果之前的线程的MDC内容没有清除掉的话，再次重线程池中获取到这个线程，会取出之前的数据(脏数据)，会导致一些不可预期的错误，所以当前线程结束后一定要清掉。所以MDC类的静态变量mdcAdapter(LogbackMDCAdapter实现)中的copyOnInheritThreadLocal会得到父类MDC写入的内容，因为它用的是。答如果都是用newThread方法建立的线程没有问题，因为之后线程会消亡。......]]></description><category></category></item><item><title><![CDATA[log(四)——MDC使用]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937730</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937730</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:09:55 +0800</pubDate><description><![CDATA[之前说过，子线程在创建的时候会把父线程中的inheritableThreadLocals变量设置到子线程的inheritableThreadLocals中，而MDC内部是用InheritableThreadLocal实现的，所以自然会把父线程中的上下文带到子线程中。对于线程池中的线程来说，这部分线程是可以重用的，但是线程本身只会初始化一次，所以之后重用线程的时候，就不会进行初始化操作了，也就不会有上一段中提到的父线程inheritableThreadLocals拷贝到子线程中的过程了。......]]></description><category></category></item><item><title><![CDATA[log(三)——MDCAdapter之实现LogbackMDCAdapter]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937718</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937718</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:09:44 +0800</pubDate><description><![CDATA[然后这个方法中的同步块也很奇怪，为什么父线程会能修改这个map，其他线程能修改这个map的地方只有通过getPropertyMap方法来获得copyOnInheritThreadLocal内容的引用，然后修改这个map的内容，只有这一处，但是一般使用MDC应该不会用getPropertyMap方法获取内容然后进行操作吧，不知道为什么把这个方法公有化，而不是包一个ImmutableMap再对外暴露。这里觉得copyonwrite依然浪费性能，所以只在get操作后做copyonwrite。......]]></description><category></category></item><item><title><![CDATA[log(二)——MDC实现之ThreadLocal]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937704</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937704</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:09:31 +0800</pubDate><description><![CDATA[在Thread的init方法中，是通过获得当前线程作为parent线程，也就是说，在哪个线程中new的这个Thread并start的，执行该操作的线程就是new的新Thread的parent线程。threadLocals保存的是当前线程中的ThreadLocal变量们，inheritableThreadLocals保存的是当前线程父线程中的变量们。但是init方法只在线程初始化的时候执行一次，所以如果用的线程池来使线程重用的话，就不会再调用这个init方法了，这会带来一些问题，后面会具体说。......]]></description><category></category></item><item><title><![CDATA[log(一)——MDC入门]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937673</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937673</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:09:21 +0800</pubDate><description><![CDATA[MDC中包装了一个MDCAdapter，这是一个接口，不同的log包有自己对应的实现。对于不支持MDC的包，比如java.util.logging，使用默认的BasicMDCAdapter，slf4j-nop有NOPMDCAdapter。简单来说就是日志的增强功能，如果配置了MDC，并添加了相应的keyvalue，就会在打日志的时候把key对应的value打印出来。内部是用ThreadLocal来实现的，可以携带当前线程的context信息。这是MDC类上的注释，但是没有讲这个是干什么的。......]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(七)——总结&补充]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937613</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937613</guid><author>xocupid</author><pubDate>Sat, 23 Jul 2022 00:09:06 +0800</pubDate><description><![CDATA[线程池的submit方法提交的任务是一个FutureTask，它既含有Runnable的任务属性也含有Future的属性。在设置异常之后，用future的get(内部是Sync的innerGet方法)方法获取结果的时候会抛出异常，线程池在执行execute方法和submit任务的时候，如果任务中抛出了异常，外部线程无法感知，所以要做一些措施来进行处理，下面就说一下产生这种效果的原因以及一些可用的处理方法。在构造线程池的时候，作为参数传递我们自己封装的线程工厂。，同时记录日志和监控。自己封装线程的工厂类。..]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(六)——线程池关闭之后]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937590</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937590</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:04:55 +0800</pubDate><description><![CDATA[上一篇主要从代码角度介绍了线程池关闭相关的方法，包括各个方法之间的逻辑关系，调用关系和产生的效果。这一篇更多从逻辑角度上来说一下线程池在shutdown之后，原来正常的处理流程有哪些变化，既是总结也是扩展。shutdown操作之后，首先最重要的一点变化就是线程池状态变成了SHUTDOWN。该状态是开始关闭线程池之后，从RUNNING改变状态经过的第一个状态(还有一种情况是直接进STOP，调用shutdownNow的时候)，有个图画的挺好，见博客。...]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(五)——线程池关闭相关操作]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937581</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937581</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:04:23 +0800</pubDate><description><![CDATA[补充了和Thread的interrupt操作相关的知识，回头再来看ThreadPoolExecutor中interrupt，关闭线程池等相关操作。


先看注释：开始一个顺序的shutdown操作，shutdown之前被执行的已提交任务，新的任务不会再被接收了。如果线程池已经被shutdown了，该方法的调用没有其他任何效果了。该方法不会等待之前已经提交的任务执行完毕，awaitTermination方法才有这个效果。具体看内部逻辑，checkShutdownAccess这个方法是确保允许调用发interr]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(四)——Interrupt]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937573</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937573</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:03:45 +0800</pubDate><description><![CDATA[Thread.interrupted()方法判断的时候返回了true，同时擦除了中断标志位，所以再用Thread.currentThread().isInterrupted()判断的时候，就返回false了。Thread的成员函数isInterrupted判断标志位的时候不会清除标志位，如果返回true，那么无论执行多少次都会返回true(期间没有其他清除标志位的操作的话)。interrupt对于正常运行的线程起不到中断作用，只是把该线程的中断标志位设置为true了，线程会继续正常运行。...]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(三)——Worker]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937559</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937559</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:03:15 +0800</pubDate><description><![CDATA[我们可以在beforeExecute方法中抛出异常，这样task不会被执行，而且在跳出该循环的时候completedAbruptly的值是true，表示theworkerdiedduetouserexception，会用decrementWorkerCount调整wc。上面说过，addWorker会用当前task创建一个Worker对象，相当于对task的包装，然后用Worker对象作为task创建一个Thread，该Thread保存在Worker的thread成员变量中。...]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(二)——execute]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937547</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937547</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:02:42 +0800</pubDate><description><![CDATA[3.如果任务无法入队列，再次尝试addWorker，这次是用正在run的线程数和maximumPoolSize比，如果超过了maximumPoolSize则reject任务，说明线程池已经饱和了。2.如果addWorker方法执行失败了，任务要入队列，如果成功入队列了，需要做doublecheck来处理一些极端情况，比如线程池是否shutdown了等等。这个代码块，首先加锁，整个类用到这个锁的地方，除了获取该线程池的一些关键参数之外，就是shutdown和terminate等相关操作。...]]></description><category></category></item><item><title><![CDATA[ThreadPoolExecutor(一)——简介]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937531</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937531</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:02:12 +0800</pubDate><description><![CDATA[一个ThreadPoolExecutor从初始化到执行需要经历如下几个环节。ThreadPoolExecutor初始化。]]></description><category></category></item><item><title><![CDATA[pool(六)——JedisPool]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937482</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937482</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 18:00:21 +0800</pubDate><description><![CDATA[和上一篇数据库连接池的PoolingDataSource一样，这个Pool类包装了对象池，里面存放了一个GenericObjectPool类型的internalPool变量。本文剖析redis.clients.jedis中关于jedis连接池部分的源码。因为只涉及连接池的部分思想，不设计具体jedis底层创建连接部分，所以篇幅很小。和jedis的创建销毁相关的工厂类。...]]></description><category></category></item><item><title><![CDATA[pool(五)——BasicDataSource]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937468</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937468</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 17:59:43 +0800</pubDate><description><![CDATA[也是从_pool这个变量中调用borrowObject拿对象，这个_pool对象就是上面说的GenericObjectPool，所以最终还是调用GenericObjectPool的borrowObject方法拿对象。可以把PoolingDataSource看作GenericObjectPool的包装，BasicDataSource的getConnection最终还是从GenericObjectPool中拿对象。query真正执行的时候，才会去获取连接。1.一次query流程。......]]></description><category></category></item><item><title><![CDATA[pool(四)——EvictionTimer]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937459</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937459</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 17:59:12 +0800</pubDate><description><![CDATA[但是如果{@linkGenericObjectPool#createCount}=={@linkGenericObjectPool#maxTotal}，{@linkGenericObjectPool#create}方法就无法继续创建对象了。该类是TimerTask的子类，run方法有两个主要功能，evict和ensureMinIdle，一个是清除对象池中过期的对象，一个是保证对象池中始终有个数为minIdle个对象。该方法中使用了EvictionPolicy来判断是对象池中的对象是否过期了。......]]></description><category></category></item><item><title><![CDATA[pool(三)——Timer]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937449</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937449</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 17:58:39 +0800</pubDate><description><![CDATA[第三个入队列，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)，到下次任务取出来判断的执行时间的时候，肯定已经超过了原本应该执行的时间。..]]></description><category></category></item><item><title><![CDATA[pool(二)——动手入门]]></title><link>https://blog.youkuaiyun.com/xocupid/article/details/125937439</link><guid>https://blog.youkuaiyun.com/xocupid/article/details/125937439</guid><author>xocupid</author><pubDate>Fri, 22 Jul 2022 17:58:06 +0800</pubDate><description><![CDATA[保证{@linkGenericObjectPool#idleObjects}对象的size和{@linkGenericObjectPool#getMinIdle}一致。但是如果{@linkGenericObjectPool#createCount}=={@linkGenericObjectPool#maxTotal}池化对象工程，这里的池化对象是MyConnection，这个工厂就是负责产生MyConnection对象的，产生的对象会放到池子中。4.对象池中对象数量控制。......]]></description><category></category></item></channel></rss>