简体   繁体   中英

OutOfMemoryError: unable to create new native thread while using Executor

I have an executor service which has a pool size of 1.

code :

@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();

    }

I am getting the OutOfMemory Error after few days of running on server. Why is this happening? Everywhere it is mentioned that the Java heap size is less we need to increase that. My understanding is, Since my thread pool size is only 1 there is only one background thread running and rest are all in queue waiting. In such case the memory allocation should be sufficient. Am i missing something , also how to fix this.

thanks

Just to supply an answer for future readers:

The main idea of the solution is to initialize the ExecutorService instance only once and reuse it on each request (see comments above).

If you use singleton resources or manually instantiate them somehow, it would be a good idea to keep the executor service as an instance field and just reference it in the operation method:

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();
    }
}

Note: As mentioned above, this is only going to work if the above resource is submitted as a singleton (using the getSingletons() method of the application class). If not, then the change has no effect as the container will be instantiating an instance of the resource on each request.

Alternatively, you could create a separate class, with a singleton instance, then call it, instead. But the most plausible workaround is to make the instance field static and set it up in a static initialization block:

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

If you have a problem with static fields, then you could create a separate singleton class instance that holds the executor service object.

For information about the singleton resources, check the JavaDocs of the Application class here: http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Application.html#getSingletons--

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM