OutOfMemoryError: unable to create new native thread while using Executor

OutOfMemoryError: unable to create new native thread while using Executor

我有一个池大小为 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", "");

            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,所以只有一个后台线程 运行,其余的都在队列中等待。在这种情况下,内存分配应该是足够的。我是否遗漏了什么,以及如何解决这个问题。

谢谢

ExecutorService 池应该是静态的(最终是最终的)。

只是为未来的读者提供答案:

解决方案的主要思想是只初始化一次 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();
    }
}

注意:如上所述,只有当上述资源作为单例提交时(使用应用程序 class 的 getSingletons() 方法),这才会起作用。如果不是,则更改无效,因为容器将在每个请求上实例化资源实例。

或者,您可以创建一个单独的 class,使用单例实例,然后调用它。但最合理的解决方法是将实例字段设为静态并将其设置在静态初始化块中:

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
                }
            });
        //...
    }
}

如果您对静态字段有疑问,那么您可以创建一个单独的单例 class 实例来保存执行程序服务对象。

有关单例资源的信息,请在此处查看应用程序 class 的 JavaDocs:http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Application.html#getSingletons--