При написании многопоточных программ следует придерживаться определённых правил, которые помогают обеспечить достойную производительность приложения в сочетании с удобной отладкой и простотой дальнейшей поддержки кода.
- Всегда давайте значимые имена своим потокам. Процесс отладки, нахождения ошибок или отслеживание исключения в многопоточном коде – довольно сложная задача.
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, т.к. первые более современны (используют все доступные на момент их написания новшества языка) и масштабируемы, чем их синхронизированые аналоги.



















