Всё для Java разработчиков.
javax.servlet и javax.servlet.http.
Основные методы сервлета:
• public void init(ServletConfig config) throws ServletException запускается сразу после загрузки сервлета в память;
• public ServletConfig getServletConfig() возвращает ссылку на объект, который предоставляет доступ к информации о конфигурации сервлета;
• public String getServletInfo() возвращает строку, содержащую информацию о сервлете, например: автор и версия сервлета;
• public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException вызывается для обработки каждого запроса;
• public void destroy() выполняется перед выгрузкой сервлета из памяти.join(), чтобы запустить поток в момент, когда другой уже закончит своё выполнение. Для реализации заданной последовательности, нужно запустить последний поток первым, и затем вызывать метод join() в обратном порядке, то есть Т3 вызывает Т2.join, а Т2 вызывает Т1.join, таким образом Т1 закончит выполнение первым, а Т3 последним. start() вызывается дважды для одного и того же объекта Thread, во время выполнения генерируется исключение.
2. Порядок, в котором запускались потоки, может не совпадать с порядком их фактического выполнения.
3. Если метод run() вызывается напрямую для объекта Thread, во время выполнения генерируется исключение.
4. Если метод sleep() вызывается для потока, во время выполнения синхронизированного кода, блокировка не снимается.
Правильный ответ: 3. Если метод run() вызывается напрямую для объекта Thread, во время выполнения исключение не генерируется. Однако, код, написанный в методе run() будет выполняться текущим, а не новым потоком. Таким образом, правильный способ запустить поток – это вызов метода start(), который приводит к выполнению метода run() новым потоком.
Вызов метода start() дважды для одного и того же объекта Thread приведёт к генерированию исключения IllegalThreadStateException во время выполнения, следовательно, утверждение 1 верно. Утверждение 2 верно, так как порядок, в котором выполняются потоки, определяется Планировщиком потоков, независимо от того, какой поток запущен первым. Утверждение 4 верно, так как поток не освободит блокировки, которые он держит, когда он переходит в состояние Ожидания.OrderProcessor, QuoteProcessor или TradeProcessor намного информативнее, чем Thread1, Thread2 и Thread3. Имя должно отражать задачу, выполняемую данным потоком.
• Избегайте блокировок или старайтесь уменьшить масштабы синхронизации. Блокировка затратна, а переключение контекста ещё более ресурсоёмко. Пытайтесь избегать синхронизации и блокировки насколько это возможно, и организуйте критическую секцию в минимально необходимом объёме. Поэтому синхронизированный блок всегда предпочительней синхронизированного метода, дополнительно наделяя возможностью абсолютного контроля над масштабом блокировки.
• Обрабатывайте прерывание потока с особой тщательностью. Нет ничего хуже оставшегося заблокированным ресурса или системы в неконстистентном, по причине неподтверждённой транзакции, состоянии.
• Помните об обработке исключений. Выброшенные InterruptedException должны быть адекватно обработаны, а не просто подавлены. Так же не стоит пренебрегать Thread.UncaughtExceptionHandler. При использовании пула потоков необходимо помнить, что он зачастую просто «проглатывает» исключения. Так, если вы отправили на выполнение Runnable нужно обязательно поместить код выполнения задачи внутрь блока try-catch. Если в очередь пула помещается Callable, необходимо удостоверится, что результат выполнения всегда изымается помощью блокирующего get(), чтобы в случае возникновения существовала возможнотсь заново выбросить произошедшее исключение.
• Между синхронизаторами и wait() и notify() следует выбирать синхронизаторы. Во-первых, синхронизаторы, типа CountDownLatch, Semaphore, CyclicBarrier или Exchanger упрощают написание кода. Очень сложно реализовывать комплексный управляющий поток, используя wait() и notify(). Во-вторых, эти классы написаны и поддерживаются настоящими мастерами своего дела и есть шанс, что в последующих версиях JDK они будут оптимизированы изнутри или заменены более производительной внешней реализацией.
• Почти всегда использование Concurrent сollection выгоднее использования Synchronized сollection, т.к. первые более современны (используют все доступные на момент их написания новшества языка) и масштабируемы, чем их синхронизированые аналоги.