Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы.
Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:
Поток для обслуживания сокета:
public void run() {
try {
while (socketListenerThread == Thread.currentThread()) {
if (selector.select() > 0)
for (Iterator<SelectionKey> i = selector.selectedKeys().iterator();
socketListenerThread == Thread.currentThread() && i.hasNext();) {
SelectionKey key = i.next();
i.remove();
if (key.isValid()) {
if (key.isConnectable()) {
SocketChannel sc = (SocketChannel) key.channel();
sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
sc.finishConnect();
} else if (key.isReadable()) {
readPacket(); // Прочитать пакет и сохранить в очереди командsynchronized (commandProcessor) {
commandProcessor.notify();
}
} else if (key.isWritable()) {
writePackets(); // Взять из очереди комманду и отослать на сервер
}
}
}
Thread.yield();
}
} catch (IOException e) {
}
... // Всё почистить за собой
}
Поток, обрабатывающий очередь команд:
public void run() {
try {
while (commandProcessorThread == Thread.currentThread()) {
synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
wait();
}
while (inputQueue.size() > 0) {
Command c = inputQueue.remove(0);
handleCommand(c);
Thread.yield();
}
}
} catch (InterruptedException e) {
} finally {
socketListenerThread = null;
if (selector != null)
selector.wakeup();
}
}
Профайлер говорит, что всё время забирают выделленные жирным строки кода. В связи с этим такие вопросы: Как это лечится, и, в принципе, правильно ли организована работа потоков?
извеняюсь что не разобрался в Вашем коде но могу точно сказать что, когда я писал много поточное приложение такого же типа у меня тоже проц грузился так. Причина — цикл функции run очень быстро крутился без задржек, я долго мучился прежде чем нашел из за чего.
Здравствуйте, xBlackCat, Вы писали:
BC>Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы. BC>Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:
BC>Поток, обрабатывающий очередь команд: BC>
BC> public void run() {
BC> try {
BC> while (commandProcessorThread == Thread.currentThread()) {
BC> synchronized (this) { // этот this == commandProcessor из верхнего куска кода.
BC> wait();
BC> }
BC> while (inputQueue.size() > 0) {
BC> Command c = inputQueue.remove(0);
BC> handleCommand(c);
BC> Thread.yield();
BC> }
BC> }
BC> } catch (InterruptedException e) {
BC> } finally {
BC> socketListenerThread = null;
BC> if (selector != null)
BC> selector.wakeup();
BC> }
BC> }
BC>
BC>Профайлер говорит, что всё время забирают выделленные жирным строки кода.
Во время Thread.yield() поток отдаёт управление другим потокам, если им есть, что делать, а сам ждёт. Пока он ждёт, ресурсы он не тратит, но время идёт.
Здравствуйте, Sahivi, Вы писали:
S>извеняюсь что не разобрался в Вашем коде но могу точно сказать что, когда я писал много поточное приложение такого же типа у меня тоже проц грузился так. Причина — цикл функции run очень быстро крутился без задржек, я долго мучился прежде чем нашел из за чего.
А можно поподробнее — какой из двух циклов Вы имеете ввиду? И как исправили?
Здравствуйте, xBlackCat, Вы писали:
BC>Здравствуйте, Lucker, Вы писали:
L>>Здравствуйте, xBlackCat, Вы писали:
BC>>>Поток, обрабатывающий очередь команд: L>>
BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.
в том то все и дело что выделенный цикл заставит поток приостанавливаться и давать возможность другим потокам занять процесорное время, пока не будет вызван нотифай и в очереди не окажется объекта.
Здравствуйте, xBlackCat, Вы писали:
BC>Чем это поможет?
BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.
кстати, если твой поток объяевлен как демон — jvm сама убъет его при завершении работы системы (если не останется ни одного не демон потока)
Здравствуйте, xBlackCat, Вы писали:
BC>Чем это поможет?
BC>И теперь нельзя будет выйти из потока не прервав его — выделенный цикл будет постоянно работать в конце работы при очереди нулевой длины.
Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?
Здравствуйте, Donz, Вы писали:
D>Во время Thread.yield() поток отдаёт управление другим потокам, если им есть, что делать, а сам ждёт. Пока он ждёт, ресурсы он не тратит, но время идёт.
Угу, обычно в ОС занято совсем не много ресурсов, вот она и отдаёт все оставшиеся этим пустым циклам.
Здравствуйте, Lucker, Вы писали:
L>Здравствуйте, xBlackCat, Вы писали:
BC>>Здравствуйте, Lucker, Вы писали:
L>>>Здравствуйте, xBlackCat, Вы писали:
BC>>>>Поток, обрабатывающий очередь команд: L>>>
L>в том то все и дело что выделенный цикл заставит поток приостанавливаться и давать возможность другим потокам занять процесорное время, пока не будет вызван нотифай и в очереди не окажется объекта.
Но разве это не то же самое, что и было? Размер очереди проверяется и так и этак. Только в моём коде проверка была вне куска synchronized.
Вопрос был ещё в другом. Чтобы не поломать логику, надо условие изменить (поправлено в коде).
Здравствуйте, xBlackCat, Вы писали:
L>>в том то все и дело что выделенный цикл заставит поток приостанавливаться и давать возможность другим потокам занять процесорное время, пока не будет вызван нотифай и в очереди не окажется объекта. BC>Но разве это не то же самое, что и было? Размер очереди проверяется и так и этак. Только в моём коде проверка была вне куска synchronized.
Ну так доступ к очереди не синхронизирован и поэтому поведение кода вообще трудно предсказать.
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, xBlackCat, Вы писали:
B>Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?
Вот я и хочу понять, чем этот код:
while (true) {
synchronized(this) {
wait();
}
while (size > 0) {
size--;
}
}
отличается от
while (true) {
synchronized(this) {
while(size == 0)
wait();
}
while (size > 0) {
size--;
}
}
Здравствуйте, xBlackCat, Вы писали:
BC>Доброго времени суток.
BC>Пишу многопоточное приложение и очень напрягает загрузка процессора под 100% во время его работы. BC>Суть приложения заключается в следующем: создать несколько подключений к серверу и посылать/принимать комманды от оного. Подключение открывается отдельным сокетом и его(подключение) обслуживают два потока — один для чтения/записи, второй для исполнения накопленных комманд от сервера. Код примерно следующий:
Многопоточный код должен работать и без Thread.yield() если многопоточность вытесняющая (а она именно такая на большинстве современных платформ).
Здравствуйте, xBlackCat, Вы писали:
B>>Весь код за тебя писать никто не будет. Lucker тебе пытается сказать что надо пересмотреть свой код и выкинуть исполнение пустых циклов. Вот скажи зачем они? Зачем каждый раз "что-то" проверять. Если можно остановить действие потка до тех пор пока "это" не поризойдет?
BC>Вот я и хочу понять, чем этот код: BC>Можете подробнее объяснить?
Самому интересно. И все же. Когда у тебя перестанут работать пустые циклы тогда и загрузка на 100% исчезнет. Скажешь что у тебя их нет?