Java 不同任务的ThreadPoolExecutor
bellow是默认的PicassoExecutorService.java,它只是从网络(和http缓存,如果之前加载的话)请求位图。比方说,如果有100个任务,95个加载到缓存中,5个来自网络,如果队列前5个中的5个,则加载5个图片时,95个图像将永远不会显示。所以,我想更改PicassoExecutorService.java,我想知道是否有可能在ExecutorService中创建一个新线程来执行磁盘缓存提取任务?我应该创建一个新队列吗 我 我对java线程编码没有太多的经验,所以我需要你的帮助,thaksJava 不同任务的ThreadPoolExecutor,java,multithreading,threadpool,Java,Multithreading,Threadpool,bellow是默认的PicassoExecutorService.java,它只是从网络(和http缓存,如果之前加载的话)请求位图。比方说,如果有100个任务,95个加载到缓存中,5个来自网络,如果队列前5个中的5个,则加载5个图片时,95个图像将永远不会显示。所以,我想更改PicassoExecutorService.java,我想知道是否有可能在ExecutorService中创建一个新线程来执行磁盘缓存提取任务?我应该创建一个新队列吗 我 我对java线程编码没有太多的经验,所以我需要你
class PicassoExecutorService extends ThreadPoolExecutor {
private static final int DEFAULT_THREAD_COUNT = 3;
PicassoExecutorService() {
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
}
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET:
setThreadCount(4);
break;
case ConnectivityManager.TYPE_MOBILE:
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_LTE: // 4G
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_EHRPD:
setThreadCount(3);
break;
case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
setThreadCount(2);
break;
case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
case TelephonyManager.NETWORK_TYPE_EDGE:
setThreadCount(1);
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
}
private void setThreadCount(int threadCount) {
setCorePoolSize(threadCount);
setMaximumPoolSize(threadCount);
}
}
static class PicassoThreadFactory implements ThreadFactory {
@SuppressWarnings("NullableProblems")
public Thread newThread(Runnable r) {
return new PicassoThread(r);
}
}
private static class PicassoThread extends Thread {
public PicassoThread(Runnable r) {
super(r);
}
@Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
super.run();
}
}
类PicassoExecutor服务扩展了ThreadPoolExecutor{
私有静态final int DEFAULT_THREAD_COUNT=3;
毕加索服务(){
super(默认线程计数,默认线程计数,0,TimeUnit.ms,
新的LinkedBlockingQueue(),新的Utils.PicassoThreadFactory();
}
无效调整线程数(网络信息){
如果(info==null | |!info.isConnectedOrConnecting()){
setThreadCount(默认线程计数);
返回;
}
开关(info.getType()){
案例连接管理器.TYPE_WIFI:
案例连接管理器.TYPE_WIMAX:
案例连接管理器.TYPE_以太网:
设置线程数(4);
打破
case ConnectivityManager.TYPE_MOBILE:
开关(info.getSubtype()){
case TelephonyManager.NETWORK\u TYPE\u LTE://4G
案例电话管理器.NETWORK\u TYPE\u HSPAP:
案例电话管理器.NETWORK\u TYPE\u EHRPD:
设置线程数(3);
打破
case TelephonyManager.NETWORK_TYPE_UMTS://3G
case TelephonyManager.NETWORK\u TYPE\u CDMA:
案例电话管理器.NETWORK\u TYPE\u EVDO\u 0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
设置线程数(2);
打破
case TelephonyManager.NETWORK_TYPE_GPRS://2G
case TelephonyManager.NETWORK_TYPE_EDGE:
设置线程数(1);
打破
违约:
setThreadCount(默认线程计数);
}
打破
违约:
setThreadCount(默认线程计数);
}
}
私有void setThreadCount(int threadCount){
setCorePoolSize(线程数);
setMaximumPoolSize(线程数);
}
}
静态类PicassoThreadFactory实现ThreadFactory{
@SuppressWarnings(“NullableProblems”)
公共线程newThread(可运行的r){
返回新的毕加索螺纹(r);
}
}
私有静态类PicassoThread扩展线程{
公共毕加索线程(可运行r){
超级(r);
}
@重写公共无效运行(){
进程。设置线程优先级(线程优先级\u后台);
super.run();
}
}
类
PicassoExecutorService
是executor服务的一个实现,它调整连接类型的线程数。也就是说,对于2G,它选择1个线程,因为2G很慢,同时设置4个线程会耗尽连接
您所面临的问题是,一些未缓存的作业会优先于缓存的请求
现在,如果能够确定是否缓存了该作业,则只需为磁盘作业创建单独的服务或线程。您向我们展示的线程池是一个连接线程,它根据连接类型限制资源。最好不要混淆这些问题,为磁盘作业创建单独的线程池
如果您在尝试从internet获取作业之前无法确定该作业是否已缓存,我将使用一种非常复杂的策略更新答案
更新
战略
首先,您需要了解所有设备上的磁盘读取超时。您需要第95个百分位超时值,例如,小于最大值的值。所以,如果你有1ms,2ms,1ms,50ms,20ms,3ms,你不能选择20ms或50ms。磁盘读取的时间为3ms。您的平均(或更好的中位数)连接超时应该大得多——比如100-500毫秒
因此,我们的想法是首先在这个小的超时时间内将作业提交到一个包含10-20个线程的线程池中。因此,它将过滤掉所有缓慢的工作
下一步是终止慢速作业。这取决于您的连接是否可中断。如果不是,那是另一个问题
在此之后,您只需将慢速作业重新提交到连接线程池。就是这样。您的
PicassoExecutorService
和PicassoThread
都是反模式的最佳示例:使用不必要的子类化。您可以同时设置ThreadPoolExecutor
的线程计数和线程的优先级,而无需创建它们的子类。我能给你的最好建议是,如果你没有java线程编码的经验,不要限制线程的数量,也不要乱搞线程优先级。那么你就没有问题中描述的问题了。在大多数情况下,您的优化是不必要的,甚至不会产生反效果。谢谢@Holger,我认为最好不要在PicassoExecutor服务中进行磁盘缓存提取,但现在我不知道如何检查映像是否在磁盘中。我会做一些研究。@Holger好吧,mike需要设法限制移动设备同时连接的数量。@AndreyChaschev我只想先显示磁盘缓存映像,而不是被网络获取映像卡住。是的,我知道了。我用一个策略更新了答案。我想看看复杂的策略,目前我不知道作业是否缓存,它是由毕加索完成的。我认为1个线程是可以的,就像毕加索ExecutorService一样,2G的线程数是1(对于磁盘提取和网络提取)。由于文件在磁盘中,我认为不会有超时,因为我们最终将获得文件。