2016-03-11 2 views
0

У меня есть сервис палача, который имеет размер пула 1.OutOfMemoryError: не удалось создать новую родную нить при использовании Исполнителя

код:

@POST 
    @Path("insertOrUpdate") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response insertOrUpdate(final String user) { 



     try { 
      new MYSQLProvider().insertOrUpdate(user); 
      resulTObj.put("success", true); 
      resulTObj.put("msg", ""); 

      ExecutorService executor = Executors.newFixedThreadPool(1); 
      executor.execute(new Runnable() { 

       @Override 
       public void run() { 
        //fetch list of all the user ids here and fire a multicast 

        log4j.info("Executor called"); 

        Map<String, String> m = new HashMap<String, String>(); 
        m.put("TAG", "MOVEMENT"); 
        m.put("user", user); 
        GCMServerJava.sendMsgToAll(m); 


       } 
      }); 

     } catch (SQLException | JSONException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      resulTObj.put("success", false); 
      resulTObj.put("msg", e.getMessage()); 
     } 




     return Response.status(200).entity(resulTObj.toString()).build(); 

    } 

Я получаю OutOfMemory Ошибки после нескольких дней работает на сервере. Почему это происходит? Всюду упоминается, что размер кучи Java меньше, мы должны увеличить это. Я понимаю, так как размер пула потоков составляет всего 1, только один фоновый поток работает и все остальные находятся в очереди. В этом случае распределение памяти должно быть достаточным. Я что-то пропустил, и как это исправить.

благодаря

+2

ли этот код, выполняющийся каждый раз, когда вам нужно запустить логику? Или вы создаете исполнителя только один раз и запускаете '' 'executor.execute ...' '' code каждый последующий раз? В первом случае количество исполнителей будет нарастать, тогда как в последнем случае задания будут передаваться одному исполнителю. –

+0

Ох! Я думаю, вы правы. Это вызвано из веб-службы при ударе запроса, но я все еще не уверен. В моем вопросе я скопировал весь код. Можете ли вы проверить и рассказать? И спасибо за ответ так скоро. –

+1

Да, вы создаете нового исполнителя и новый поток для каждого запроса. Таким образом, потоки накапливаются, и в итоге у вас заканчивается память. Переместите инициализацию исполнителя из метода, поэтому он создается только один раз, и проблема должна быть исправлена. – jmruc

ответ

2

Просто дать ответ для будущих читателей:

Основная идея решения заключается в инициализации экземпляра ExecutorService только один раз и использовать его на каждом запросе (см комментарии выше).

При использовании одноэлементных ресурсов или вручную создать экземпляр их так или иначе, это было бы хорошая идея, чтобы сохранить службу исполнителя в поле экземпляра и просто ссылаться на него в методе работы:

public class MySqlResource{ 

    private final ExecutorService executor; 

    public MySqlResource() { 
     this.executor = Executors.newFixedThreadPool(1); 
    } 

    @POST 
    @Path("insertOrUpdate") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response insertOrUpdate(final String user) { 

     try { 
      new MYSQLProvider().insertOrUpdate(user); 
      resulTObj.put("success", true); 
      resulTObj.put("msg", ""); 

      executor.execute(new Runnable() { 

       @Override 
       public void run() { 
        //...run() code goes here 
       } 
      }); 
     } catch (SQLException | JSONException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      resulTObj.put("success", false); 
      resulTObj.put("msg", e.getMessage()); 
     } 

     return Response.status(200).entity(resulTObj.toString()).build(); 
    } 
} 

Примечания: Как упомянутый выше, это будет работать только в том случае, если вышеуказанный ресурс представлен как одноэлементный (с использованием метода класса приложения). Если нет, то изменение не влияет, поскольку контейнер будет создавать экземпляр ресурса для каждого запроса.

В качестве альтернативы вы можете создать отдельный класс с экземпляром singleton, а затем вызвать его. Но наиболее правдоподобный обходной путь, чтобы сделать поле экземпляра статическим и установить его в статическом блоке инициализации:

public class MySqlResource { 

    //Note that the field is now static 
    private static final ExecutorService executor; 

    static { 
     MySqlResource.executor = Executors.newFixedThreadPool(1); 
    } 

    //..... 
    //Then the method can invoke it just as in the previous solution: 
    public Response insertOrUpdate(final String user) { 
     //... 
     MySqlResource.executor.execute(new Runnable() { 

       @Override 
       public void run() { 
        //...run() code goes here 
       } 
      }); 
     //... 
    } 
} 

Если у вас есть проблемы со статическими полями, то вы можете создать отдельный экземпляр одноплодного класса, который держит объект сервиса-исполнителя.

Для получения информации о одноэлементных ресурсов, проверьте JavaDocs класса Application здесь: http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Application.html#getSingletons--

0

ExecutorService пул должен быть статическим (и в конечном счете, окончательный).

Смежные вопросы