Java 不同任务的ThreadPoolExecutor

Java 不同任务的ThreadPoolExecutor,java,multithreading,threadpool,Java,Multithreading,Threadpool,bellow是默认的PicassoExecutorService.java,它只是从网络(和http缓存,如果之前加载的话)请求位图。比方说,如果有100个任务,95个加载到缓存中,5个来自网络,如果队列前5个中的5个,则加载5个图片时,95个图像将永远不会显示。所以,我想更改PicassoExecutorService.java,我想知道是否有可能在ExecutorService中创建一个新线程来执行磁盘缓存提取任务?我应该创建一个新队列吗 我 我对java线程编码没有太多的经验,所以我需要你

bellow是默认的PicassoExecutorService.java,它只是从网络(和http缓存,如果之前加载的话)请求位图。比方说,如果有100个任务,95个加载到缓存中,5个来自网络,如果队列前5个中的5个,则加载5个图片时,95个图像将永远不会显示。所以,我想更改PicassoExecutorService.java,我想知道是否有可能在ExecutorService中创建一个新线程来执行磁盘缓存提取任务?我应该创建一个新队列吗 我 我对java线程编码没有太多的经验,所以我需要你的帮助,thaks

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(对于磁盘提取和网络提取)。由于文件在磁盘中,我认为不会有超时,因为我们最终将获得文件。