求教一个 Java 线程池的问题

2022-09-02 09:56:59 +08:00
 abc0123xyz

ThreadPoolExecutor 创建线程池
Callable 接口的实现类处理逻辑

在实现类的 call()中,每次都要访问一个资源,这一步要耗时很久。持有这个资源的对象其实是可以复用的,怎么样才可以让线程本身持有这个资源?或者各位大佬给点其他思路

3171 次点击
所在节点    Java
25 条回复
Bluelion
2022-09-02 10:05:07 +08:00
ThreadLocal
beetlerx
2022-09-02 10:05:47 +08:00
那就放 threadLocal 里呗
L0L
2022-09-02 10:15:42 +08:00
1 、ThreadLocal 直接定义最简单;
2 、或者使用自定义 ThreadFactory ,来自定义线程池内线程,构建时组合一个资源;
3 、我看你的描述,这个对象如果是可以复用的,为什么不通过单例来做呢,简单又高效(注意:没有线程安全的问题情况下)。
lmshl
2022-09-02 10:20:27 +08:00
放资源池不就行了,学 jdbc 的 connection pool 呗。
shanghai1943
2022-09-02 10:21:16 +08:00
你是想在单个线程里复用还是线程池里复用?
abc0123xyz
2022-09-02 10:28:04 +08:00
@L0L #3 这个对象只能同时处理一个,多个线程同时调用的时候会其他的就要等待了。

现在 call()中每次都新建是因为,这个对象不是很可靠,有时候会出问题,一旦出问题,这个对象可能就用不了了,所以需要销毁重新 new 。

其实我是希望对象本身可以服用,处理过程中一旦抛出异常或超出一定时间,就把对象销毁重新 new
abc0123xyz
2022-09-02 10:29:50 +08:00
@lmshl #4
@Bluelion #1
@beetlerx #2
感谢各位大佬
我研究一下,平时一直都在增删改查,没处理过这种东西
dqzcwxb
2022-09-02 10:31:22 +08:00
用 Caffeine 做缓存全局共享前提是你的共享对象只读不写,ThreadLocal 存在父子线程传递问题要是你不传递你就得每个线程都去创建
abc0123xyz
2022-09-02 10:32:20 +08:00
@shanghai1943 #5
都可以,线程池中复用应该更好
ForkNMB
2022-09-02 10:32:25 +08:00
FastThreadLocal
L0L
2022-09-02 10:54:54 +08:00
@abc0123xyz
本质上你这个资源是线程不安全的,你需要同步方法来保证执行过程中的安全;如果是我来写的话,我可能还是会优先使用单例。
* 在获取单例的时候,校验下该对象是否可用;
* 如果对象不可用的话会,重新构建一个单例对象出来,替换原本的对象;
* 同时执行具体方法的时候,加上同步锁,保证当前只有一个线程执行具体的方法。

实现起来方法多种多样,只要能满足需求,都是好的方法。
timethinker
2022-09-02 11:09:45 +08:00
这个对象有没有可能创建多个实例,每一个线程使用自己所绑定的那一个?这样线程之间就不用竞争,也无需加锁。

具体的做法就是,在线程池中的其中一个线程执行你的代码的时候:
1 、从 ThreadLocal 取出这个对象。
2 、如果不存在,实例化这个对象并对它进行初始化,然后再保存到 ThreadLocal 里面。
3 、使用这个对象。

这样当下一次这个线程再次执行时,就可以省略掉第二个步骤,对象就可以得到复用。

至于你说的这个对象有可能会损坏,你可以创建一个类来包装并代理委托执行相关的方法,通过封装内部实际对象,就可以对异常进行处理,比如重新构造内部实际对象,这样外部的代码就可以不用关心内部的处理流程。但是如果异常是必须要在业务逻辑中进行处理的,就不能通过代理类对这些异常进行掩盖,以免导致意外的 BUG 。
xsqfjys
2022-09-02 11:14:46 +08:00
好奇怪的场景,一个不可靠的对象可还行
hidemyself
2022-09-02 11:22:39 +08:00
apache commons pool2 看一下这个
DavidDee
2022-09-02 11:32:29 +08:00
比较好奇,这个对象是怎么变为不可靠的呢
abc0123xyz
2022-09-02 11:35:27 +08:00
@xsqfjys #13
@DavidDee #15
其实就 java 调用第三方工具,第三方卡死,所以这个对象就没用了,要重新 new 一个
zmal
2022-09-02 12:02:12 +08:00
这不就是连接池的适用场景么
ma836323493
2022-09-02 15:09:53 +08:00
看你说的像是多个线程复用, 那就个一个静态 引用 ,然后 用 lock 把线程中使用的地方 lock 起来
urnoob
2022-09-02 15:22:34 +08:00
可参考 guava cache
所有线程执行的 call 方法中都是从 cache 中取(“读”)这个实例。当没有的时候就,guava cache 会调用你在创建 cache 时定义的加载这个实例的方法。剩下的就是做好线程同步即可 避免重复加载即可。
goldenAndGreen
2022-09-02 15:22:34 +08:00
apache object pool, 线程从池子里取对象

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/877178

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX