Не понимание java.awt.EventQueue.invokeAndWait
действия, как будто это содержит блокировку (эксклюзивный доступ к Потоку Отправки События, EDT). Большая вещь о мертвых блокировках состоит в том, что, даже если это редко происходит, можно захватить отслеживание стека с jstack и т.п. Я видел это во многих широко используемых программах (фиксация к проблеме, которую я только видел, происходят, как только в Netbeans должен быть включен в следующий выпуск).
Стартовый RMI Java заставляет фоновую задачу работать, который вынуждает сборщик "мусора" работать каждые 60 секунд. Сам по себе это может быть хорошей вещью, однако может случиться так, что сервер RMI не был запущен Вами непосредственно, но платформой/инструментом Вы используете (например, JRun). И, RMI не мог бы на самом деле использоваться ни для чего.
конечным результатом является System.gc () вызов однажды минута. В в большой степени загруженной системе Вы будете видеть следующий вывод в своих журналах - 60 секунд действия, сопровождаемого длинной паузой gc, сопровождаемой на 60 секунд действия, сопровождаемого длинной паузой gc. Это является фатальным для пропускной способности.
решение состоит в том, чтобы выключить явный gc, использующий-XX: + DisableExplicitGC
Условия состязания во время объекта завершать/выпускать/завершать работу/деструктор метод и нормальные вызовы.
От Java, я делаю большую интеграцию с ресурсами, которые должны быть закрыты, такие как COM-объекты или Flash player. Разработчики всегда забывают делать, это правильно и заканчивать тем, что имело поток называет объект, который был завершением работы.
Отказ предоставить ясно определенные методы жизненного цикла на объектах, которые управляют продолжительными потоками. Мне нравится создавать пар методов, названных init () и уничтожать (). Также важно на самом деле звонить, уничтожают (), таким образом, Ваше приложение может выйти корректно.
Поддержание занятости всех потоков.
Это является самым частым с необходимостью пойти, решают проблемы в коде других людей, потому что они неправильно использовали конструкции блокировки. С последнего мои коллеги, кажется, нашли блокировки читателя/писателя довольно забавными опрыснуть вокруг, тогда как немного мысли устраняет их необходимость полностью.
В моем собственном коде, поддержание занятости потоков менее очевидно, но сложно. Это требует, чтобы более глубокая мысль в алгоритмы, такие как запись новых структур данных или тщательно разработка системы гарантировала, что, когда блокировка используется, с этим никогда не будут спорить.
параллелизм Решения путает, легко - пытающийся выяснить, как избежать, чтобы конкуренция за блокировку могла быть трудной.
Метод, сохраняющий данные к переменной экземпляра для "сохранения усилий" передача его к вспомогательным методам, когда другой метод, который можно назвать одновременно, использует те же переменные экземпляра в своих собственных целях.
данные должны вместо этого быть розданы как параметры метода на время синхронизируемого вызова. Это - только небольшое упрощение моей худшей памяти:
public class UserService {
private String userName;
public String getUserName() {
return userName;
}
public void login(String name) {
this.userName = name;
doLogin();
}
private void doLogin() {
userDao.login(getUserName());
}
public void delete(String name) {
this.userName = name;
doDelete();
}
private void doDelete() {
userDao.delete(getUserName());
}
}
методы входа в систему и выхода из системы не должны синхронизироваться, логически говоря. Но записанный как есть Вы получаете к expeience все виды забавных вызовов обслуживания клиентов.
Проблема параллелизма использования различных объектов блокирования с ожиданием и уведомляет.
я пытался использовать, ожидают () и notifyAll () методы, и вот то, как я использовал и упал в аду.
Thread1
Object o1 = new Object();
synchronized(o1) {
o1.wait();
}
И в другом потоке. Поток - 2
Object o2 = new Object();
synchronized(o2) {
o2.notifyAll();
}
Thread1 будет ожидать на o1 и Thread2, который должен был вызвать o1.notifyAll (), вызов o2.notifyAll (). Поток 1 никогда не будет просыпаться.
И offcourse типичная проблема не вызова ожидает () или notifyAll () в синхронизируемых блоках и не вызове их использующий тот же объект, который привык к sycnhronze блок.
Object o2 = new Object();
synchronized(o2) {
notifyAll();
}
Это вызовет IllegalMonitorStateException, так как поток, который вызвал notifyAll () вызвал notifyAll () использующий этот объект, но не является владельцем этого объекта блокирования. Но текущий поток является владельцем o2 объекта блокирования.
1) частая ошибка, с которой я встретился, включает итерацию по синхронизируемому классу Набора. Это требуется, чтобы, вручную синхронизировался прежде, чем получить итератор и при итерации.
2) Другая ошибка состоит в том, что большинство учебников производит впечатление, что создание ориентированного на многопотоковое исполнение класса является просто вопросом добавления синхронизируемого на каждом методе. Это сам по себе не гарантия - она только защитит целостность конкретного класса, но результаты могут все еще быть не детерминированы.
3) Помещение слишком много дорогостоящие временем операции в синхронизируемом блоке часто приводят к очень плохой производительности. К счастью, будущий шаблон в пакете параллелизма может безопасный день.
4) Кэширующиеся изменяемые объекты улучшить производительность часто приводят к проблемам многопоточности также (и иногда очень трудно отслеживать, так как Вы предполагаете, что Вы - единственный пользователь).
5) Используя несколько объектов синхронизации должен быть тщательно обработан.
Так как Java 5 там является Thread.getUncaughtExceptionHandler, но этот UncaughtExceptionHandler никогда не называют, когда ExecutorService/ThreadPool используется.
, По крайней мере, я не смог получить UncaughtExceptionHandler с работой ExcutorService.
Я столкнулся с псевдомертвой блокировкой от потока ввода-вывода, который создал фиксатор обратного отсчета. Значительно упрощенная версия проблемы похожа:
public class MyReader implements Runnable { private final CountDownLatch done = new CountDownLatch(1); private volatile isOkToRun = true; public void run() { while (isOkToRun) { sendMessage(getMessaage()); } done.countDown(); } public void stop() { isOkToRun = false; done.await(); } }
идея остановки () состоит в том, что она не возвратилась, пока поток не вышел, поэтому когда она возвратилась, система была в известном состоянии. Это в порядке, если sendMessage () не приводит к вызову остановки (), где это будет ожидать навсегда. Пока остановка () никогда не вызывается от Выполнимого, все будет работать, как Вы ожидаете. В крупном приложении, однако, действие потока Runnable не может быть очевидным!
решение состояло в том, чтобы звонить, ждут () с тайм-аутом нескольких секунд, и зарегистрировать дамп стека и жалобу любое время, тайм-аут произошел. Это сохранило желаемое поведение, когда это было возможно, и представило проблемы кодирования, поскольку с ними встретились.
Помощь с Реализацией Агентов в Функциональном Java и сравнительном тестировании миллионов потоков на многоядерных машинах.
Самой большой проблемой, на которую я натыкался, являются разработчики, которые добавляют поддержку многопоточности машинально.
Мои два цента при том, чтобы стараться избегать проблем синхронизации от запуска — не упускают следующие проблемы/запахи:
new Thread()
являются запахом . Используйте выделил ExecutorServices вместо этого, которые вынуждают Вас думать о полном понятии поточной обработки своего приложения (см. 1), и поощрите других следовать за ним. AtomicBoolean
и др. , синхронизировал Наборы, и т.д.). Снова: примите сознательное решение о том, важна ли потокобезопасность в данном контексте, не просто используйте их вслепую. public class ThreadA implements Runnable {
private volatile SharedObject obj;
public void run() {
while (true) {
obj = new SharedObject();
obj.setValue("Hallo");
}
}
public SharedObject getObj() {
return obj;
}
}
проблема я пытаюсь указать здесь (среди других), то, что сброс SharedObject obj происходит прежде, чем установить значение "Привет". Это означает, что потребитель getObj () мог бы получить экземпляр, куда getValue () возвращает пустой указатель.
public class ThreadB implements Runnable {
ThreadA a = null;
public ThreadB(ThreadA a) {
this.a = a;
}
public void run() {
while (true) {
try {
System.out.println("SharedObject: " + a.getObj().getVal());
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SharedObject {
private String val = null;
public SharedObject() {
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
}
while(true)
{
if (...)
break
doStuff()
}
Неизменно, когда разработчики пишут циклы с условием продолжения, они пропускают "фиксацию ресурса" в их собственном коде.
А именно, если тот блок не выходит, приложение и возможно даже, система запрется и умрет. Только из-за простого while(fantasy_land)...if(...) break
.
Обновление компонента пользовательского интерфейса Swing (обычно индикатора выполнения) в рабочем потоке, а не в потоке Swing (конечно, следует использовать SwingUtilities.invokeLater (Runnable)
, но если вы забудете это сделать, ошибка может проявиться долго.)
Неприятное попадание, которое я нашел в java, заключается в том, что несколько потоков получают доступ к HashMap без синхронизации. Если читатель читает и пишет, то есть большая вероятность того, что читатель окажется в бесконечном цикле (в зацикленном списке повреждена структура ведерного списка узлов).
Очевидно, что это делать вообще не стоит (используйте ConcurrentHashMap или Collections. synch... wrapper), но, похоже, именно она всегда проникает в сеть и приводит к застреванию нужного потока, система полностью ломается, обычно из-за того, что класс утилиты, содержащий такую карту, находится на нескольких уровнях внизу стека и никто об этом не задумывается.
.