Потоки, запущенные с AsyncHttpClient и Quartz Job

Вот простой планировщик Quartz, который должен запускать задание раз в минуту; задание само по себе делает HTTP-запрос, используя Sonatype Async Http Client. Используя jvisualvm, я смог обнаружить потоки, порождаемые и никогда не закрывающиеся, например. они застряли в ожидании. Это наводит меня на мысль, что либо А) я неправильно понимаю, как Quartz работает с этой конкретной настройкой, либо Б) что-то еще не так. Наверное А :) Планировщик:

public class QuartzAsyncHttpThreadTest {

    /* TEST */
    @SuppressWarnings("rawtypes")
    private static Class jobToRun = AsyncHttpRequestJob.class;
    private static String cron = "0 0/1 * * * ?";
    /* TEST */


    public static void main(String[] args) throws SchedulerException {

        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        scheduler.start();

        start(scheduler, jobToRun.getName(), jobToRun);

    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void start(Scheduler scheduler, String name, Class job)
            throws SchedulerException {

        JobKey monitorKey = new JobKey(name + "_job", "jobs");
        JobDetail detail = JobBuilder.newJob(job).withIdentity(monitorKey)
                .build();

        Trigger cronDef = TriggerBuilder.newTrigger()
                .withIdentity(name + "_trigger", "triggers")
                .withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();

        scheduler.scheduleJob(detail, cronDef);

    }

}

Работа:

public class AsyncHttpRequestJob implements Job {

    public AsyncHttpRequestJob() {

    }

    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        System.out.println("Go..");

        makeRequest();

    }

    public static void makeRequest() {

        try {

            Future<Response> r = new AsyncHttpClient().prepareGet(
                    "http://google.com").execute();

            Response response = r.get();

            System.out.println("Request status: " + response.getStatusCode()); // 301

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

Там действительно не так много. Если я профилирую живые темы, посягательство заметно уже через 2 минуты. Сначала 24, потом 27, 30... и так далее. введите здесь описание изображения

ИЗМЕНИТЬ:

Я смог убедиться, что это комбинация AsyncHttpClient и Quartz, например, когда я заменил метод makeRequest стандартным запросом:

    URL conn = new URL("http://google.com");
    URLConnection httpR = conn.openConnection();
    BufferedReader in = new BufferedReader(new InputStreamReader(
            httpR.getInputStream()));
    String inputLine;

    while ((inputLine = in.readLine()) != null)
        System.out.println(inputLine);
    in.close();

Все работает как положено.


person Community    schedule 15.10.2012    source источник
comment
Можете ли вы сделать дамп застрявших потоков (например, с помощью jvisualvm)? Они висят на r.get()? Отображается ли когда-нибудь "Request status: "? И зачем использовать асинхронный клиент, если вы все равно ждете ответа синхронно?   -  person Tomasz Nurkiewicz    schedule 16.10.2012
comment
В документе сказано, что это блокирующий способ его использования, не так ли? Так что я подумал, что это не должно иметь значения. Я вижу, что статус запроса зарегистрирован. Я могу сделать дамп потоков, но то, что появляется каждый раз, — это поток AsyncHttpClient-Reaper, изображенный на изображении.   -  person    schedule 16.10.2012


Ответы (1)


Вы должны закрыть каждый экземпляр AsyncHttpClient, созданный здесь:

Future<Response> r = new AsyncHttpClient().prepareGet(
                "http://google.com").execute();

используя close() метод. Каждый экземпляр AsyncHttpClient создает некоторые ресурсы (например, потоки), которые необходимо очистить).

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

Наконец, поскольку вы в основном отправляете какой-то запрос и ожидаете синхронно (блокируя) ответа, почему бы не использовать стандартный URLConnection (как в вашем примере) или HttpClient? AsyncHttpClient отлично подходит, когда вы не хотите синхронно ждать ответа, например. когда вы хотите инициировать сотни HTTP-запросов одновременно, не создавая сотни потоков. Затем AsyncHttpClient будет вызывать ваш код обратного вызова по мере появления ответов.

person Tomasz Nurkiewicz    schedule 16.10.2012