Проблема при выполнении асинхронных задач с помощью ExecutorService

Я задал вопрос ранее относительно инициализации ExecutorService и Apache Velocity. Чтобы дать краткий обзор - у меня есть интерфейс Java EE, который принимает запросы пользователей, а затем для каждого из этих запросов использует ExecutorService (SingleThreadedExecutor, установленный как демон), чтобы запустить длительный рабочий процесс. Этот рабочий процесс содержится в библиотеке и работает ну и как положено при запуске в автономном режиме через eclipse. При вызове с веб-сайта (сервлета) я заметил, что рабочие процессы постоянно зависали в точке, где инициализировался Velocity Engine (Velocity.init() или ve.init()). Отсюда мой вышеупомянутый вопрос.

Когда ни один из ответов/предложений не сработал, я сделал вывод, что это как-то связано с запуском Velocity, и решил перейти на FreeMarker. Теперь я вижу, что рабочий процесс зависает в том же месте и для реализации FreeMarker. Это «место» является частью создания почты, которая оценивает шаблон по паре переданных объектов данных и возвращает почтовую строку. Класс, который вызывает класс Freemark'ing и класс FreeMark, выглядит следующим образом:

   public class mailBuilder {

    private static final Logger log = Logger.getLogger( mailBuilder.class );    
    static String a;
    static String b;

    public mailBuilder(CustomDataStructure input)
    {
        a = input.getA();
        b = input.getB(); 
    }
    public static String returnMailstring() throws Exception
    {
        log.info("Gathering elements to construct email.");
        String mailText=null;
        Map context = new HashMap();
        context.put("a",a);
        context.put("b",b);
        log.info("Calling Freemarker");
        mailText=FreeMarkIT.ReturnReportString(context);
        log.info("Freeemarker returned string");

        return mailText;
    }
}

Класс FreeMarkIT выглядит следующим образом:

    public class FreeMarkIT {
        private static final Logger log = Logger.getLogger( FreeMarkIT.class );
        private static Configuration config;
        private static Template template;

        public static String ReturnReportString(Map model) throws IOException, TemplateException
        {
            StringWriter sw = new StringWriter();
            try 
            {
               log.info("Going to get the template");
               config= new Configuration();
               log.info("Now really");
               template=config.getTemplate("src/resource/email_template.vm");
               log.info("Done initializing template");
               template.process(model, sw);
               sw.flush();
            }
            catch(Exception e)
            {
                System.out.println(e.getMessage());
            }

            return sw.getBuffer().toString();
        }
    }

Теперь из моего лога видно, что рабочий поток зависает на строке config=new Configuration()

Опять же, это работает, как и ожидалось, в автономном режиме при запуске из eclipse, но, тем не менее, зависает при вызове из сервлета с использованием ExecutorService.

Я начинаю думать/понимать, что это может не иметь ничего общего ни с Velocity, ни с FreeMarker, а иметь какое-то отношение к ExecutorService. Любой совет или предложение будет иметь огромную помощь.

Спасибо


person ping    schedule 01.01.2012    source источник
comment
Ваш код не является допустимым кодом Java. Что точно, так это то, что он очень далек от потокобезопасности. Покажите нам настоящий код, потому что все исправления, которые мы можем сделать с поддельным кодом, не принесут пользы. И, пожалуйста, соблюдайте соглашения об именах Java: ваш код трудно читать.   -  person JB Nizet    schedule 01.01.2012
comment
Я прошу прощения. Я исправил код сейчас.   -  person ping    schedule 01.01.2012


Ответы (1)


ваш код не является потокобезопасным, поскольку вы совместно используете config и template во всех экземплярах потока (и постоянно их переустанавливаете). Самый простой способ сделать его потокобезопасным — создать config и template локальные переменные в методе вместо статических членов. как отметил @JBNizet в комментариях, у вас есть аналогичная проблема в mailBuilder с a и b. возможно, вы захотите сначала ознакомиться с некоторыми учебными пособиями по основам объектно-ориентированного программирования, а затем вернуться к этой проблеме (подсказка, в целом вам следует избегать статических переменных-членов, за исключением констант).

person jtahlborn    schedule 01.01.2012
comment
+1. Переменные a и b и метод returnMailstring в mailBuilder также не должны быть статическими. - person JB Nizet; 01.01.2012
comment
Ах, но не будет ли к ним обращаться только 1 поток из-за того, что ExecutorService является SingleThreadedExecutor? Я пробую ваше предложение прямо сейчас. - person ping; 01.01.2012
comment
Мы не видели, как ты используешь своего исполнителя. У вас есть как минимум два потока: поток обработки запросов и рабочий поток. Ваш код не только не является потокобезопасным, но и плохо спроектирован. Начните с устранения проблем с дизайном и по крайней мере посмотрите, решит ли это проблему. - person JB Nizet; 01.01.2012
comment
Я попробовал это и могу сказать, что проблема остается. Мой исполнитель основан на ответе nos в следующем потоке --stackoverflow.com/questions/4907502/ - person ping; 01.01.2012
comment
@ping — опубликуйте свой обновленный код и дамп потока, показывающий, где ваш код застрял - person jtahlborn; 01.01.2012
comment
Как примечание, объекты FreeMarker Configuration и Template являются потокобезопасными, если вы не вызываете их методы-мутаторы явно, и вы этого не делаете. (Код по-прежнему не имеет смысла, потому что экземпляр Configuration не используется повторно, но хранится в поле.) Но модель данных (контекст), к которой вы обращаетесь из шаблона FreeMarker, никоим образом не синхронизируется FreeMarker. . Таким образом, модель данных должна быть потокобезопасной, если вы разделяете ее между несколькими потоками, запускающими FreeMarker. - person ddekany; 02.01.2012
comment
@jtahlborn В конце концов, это было из-за того, что мои классы не были потокобезопасными. Делая их такими, проблема решалась. Я иду вперед и принимаю ваш ответ. Теперь мне нужно понять необходимость обеспечения безопасности потоков при использовании SingleThreadedExecutor. Спасибо за помощь. - person ping; 02.01.2012