Отправка кодировки в заголовки всегда хорошая идея.
Если это невозможно, тэг имеет свойство
charset
. Ссылка на W3C
Из Википедии:
Потокобезопасность - это концепция компьютерного программирования, применяемая в контексте многопоточных программ. Часть кода является поточно-ориентированной, если она работает правильно при одновременном выполнении несколькими потоками. В частности, он должен удовлетворять потребность нескольких потоков в доступе к одним и тем же общим данным, а также необходимость доступа к общему фрагменту данных только одному потоку в любой момент времени.
Есть несколько способов достижения безопасности потока:
Повторный вход:
Написание кода таким образом, что он может быть частично выполнен одной задачей , повторно введенный другой задачей, а затем возобновленный с исходной задачи. Это требует сохранения информации о состоянии в переменных, локальных для каждой задачи, обычно в ее стеке, а не в статических или глобальных переменных.
Взаимное исключение:
Доступ к совместно используемым данным сериализуется с использованием механизмов, которые гарантируют, что только один поток читает или записывает совместно используемые данные в любое время. Требуется большая осторожность, если фрагмент кода обращается к нескольким совместно используемым частям данных - проблемы включают в себя условия гонки, взаимоблокировки, блокировки в реальном времени, голодание и различные другие проблемы, перечисленные во многих учебниках по операционным системам.
Локальное хранилище потока:
Переменные локализованы так, что каждый поток имеет свою собственную личную копию. Эти переменные сохраняют свои значения в пределах подпрограммы и других границ кода и являются поточно-ориентированными, поскольку они локальны для каждого потока, даже если код, который обращается к ним, может быть повторно входящим.
Атомарные операции:
Доступ к общим данным осуществляется с помощью атомарных операций, которые не могут быть прерваны другими потоками. Обычно это требует использования специальных инструкций машинного языка, которые могут быть доступны в библиотеке времени выполнения. Поскольку операции являются атомарными, общие данные всегда сохраняются в допустимом состоянии независимо от того, какие другие потоки обращаются к ним. Атомарные операции составляют основу многих механизмов блокировки потоков.
читать дальше:
http://en.wikipedia.org/wiki/Thread_safety
на немецком языке: http://de.wikipedia.org/wiki/Threadsicherheit
на французском языке: http: // fr .wikipedia.org / wiki / Threadsafe (очень короткий)
Давайте ответим на это на примере:
class NonThreadSafe {
private int counter = 0;
public boolean countTo10() {
count = count + 1;
return (count == 10);
}
Метод countTo10
добавляет единицу к счетчику и затем возвращает true, если счетчик достиг 10. Он должен возвращать true только один раз.
Это будет работать, пока только один поток выполняет код. Если два потока запускают код одновременно, могут возникнуть различные проблемы.
Например, если count начинается с 9, один поток может добавить 1 к счету (делая 10), но затем второй поток может войти в метод и снова добавить 1 (делая 11), прежде чем первый поток сможет выполнить сравнение с 10. Затем оба потока выполняют сравнение и обнаруживают, что счетчик равен 11, и ни один из них не возвращает true.
Так что этот код не является потокобезопасным.
По сути, все проблемы с многопоточностью вызваны некоторой вариацией такого рода проблем.
Решение состоит в том, чтобы гарантировать, что сложение и сравнение не могут быть разделены (например, путем окружения двух операторов каким-либо кодом синхронизации) или путем разработки решения, которое не требует двух операций. Такой код будет поточно-ориентированным.
Проще говоря: P Если безопасно выполнить несколько потоков в блоке кода, это потокобезопасно *
* применяются условия
Условия упоминаются другими ответами, такими как 1. Результат должен быть таким же, если вы выполняете один поток или несколько потоков над ним и т. Д.
Да и да. Это означает, что данные не изменяются более чем одним потоком одновременно. Тем не менее, ваша программа может работать, как ожидалось, и выглядеть поточно-ориентированной, даже если это принципиально не так.
Обратите внимание, что непредсказуемость результатов является следствием «состояния гонки», которое, вероятно, приводит к изменению данных в порядке, отличном от ожидаемого.
Проще понять, что делает код не поточно-ориентированным. Есть две основные проблемы, которые приведут к тому, что многопоточное приложение будет иметь нежелательное поведение.
Доступ к общей переменной без блокировки
Эта переменная может быть изменена другим потоком во время выполнения функции. Вы хотите предотвратить это с помощью механизма блокировки, чтобы быть уверенным в поведении вашей функции. Общее эмпирическое правило заключается в том, чтобы сохранить блокировку на максимально короткое время.
Дедлок, вызванный взаимной зависимостью от общей переменной
Если у вас есть две общие переменные A и B. В одной функции вы сначала блокируете A, а затем блокируете B. В другой функции вы запускаете блокировка B и через некоторое время вы блокируете A. Это потенциальная тупиковая ситуация, когда первая функция будет ожидать разблокировки B, когда вторая функция будет ожидать разблокировки A. Эта проблема, вероятно, не будет возникать в вашей среде разработки и только время от времени. Чтобы избежать этого, все блокировки всегда должны быть в одном и том же порядке.
Поток-безопасный код работает, как указано, даже если он вводится одновременно разными потоками. Это часто означает, что внутренние структуры данных или операции, которые должны выполняться непрерывно, защищены от различных модификаций одновременно.
Я хотел бы добавить больше информации к другим хорошим ответам.
Безопасность потоков подразумевает, что несколько потоков могут записывать / считывать данные в одном и том же объекте без ошибок несовместимости памяти. В многопоточных программах многопоточная программа не вызывает побочных эффектов для общих данных .
Посмотрите на этот вопрос SE для более подробной информации:
Что означает потокобезопасность?
Поточно-ориентированная программа гарантирует согласованность памяти [тысяча сто сорок-два]. [+1135] Из страницы документации оракула по расширенному параллельному API: Свойства согласованности памяти: Глава 17 Спецификации языка Java ™ определяет отношение «происходит до» в операциях с памятью, таких как чтение и запись общих переменных. Результаты записи одним потоком гарантированно будут видимы для чтения другим потоком, только если операция записи происходит - до операции чтения . Конструкции Методы всех классов в synchronized
и volatile
, а также методы Thread.start()
и Thread.join()
могут образовывать отношения , предшествующие . java.util.concurrent
и его подпакетах расширяют эти гарантии до синхронизации более высокого уровня. В частности:
Runnable
в Executor
происходят до того, как начнется его выполнение. Аналогично для Callables, представленных в ExecutorService
. Future
действиями до события после получения результата через Future.get()
в другом потоке. Lock.unlock, Semaphore.release, and CountDownLatch.countDown
, выполняются перед действиями после успешного метода «получения», такого как Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await
, на том же объекте синхронизатора в другом потоке. Exchanger
, действия, предшествующие exchange()
в каждом потоке, выполняются до действий, следующих за соответствующим exchange () в другом потоке. CyclicBarrier.await
и Phaser.awaitAdvance
(а также их варианты) происходят перед действиями, выполняемыми барьерным действием, и действиями, выполняемыми барьерным действием, выполняются до действий, следующих за успешным возвратом из соответствующего жду в других темах.
Как уже отмечали другие, безопасность потоков означает, что фрагмент кода будет работать без ошибок, если он используется более чем одним потоком одновременно.
Стоит помнить, что иногда это требует затрат компьютерного времени и более сложного кодирования, поэтому это не всегда желательно. Если класс можно безопасно использовать только в одном потоке, лучше сделать это.
Например, Java имеет два класса, которые почти эквивалентны, StringBuffer
и StringBuilder
. Разница в том, что StringBuffer
является потокобезопасным, поэтому один экземпляр StringBuffer
может использоваться несколькими потоками одновременно. StringBuilder
не является поточно-ориентированным и разработан как замена с более высокой производительностью для тех случаев (подавляющего большинства), когда строка строится только одним потоком.
Мне нравится определение из Java-параллелизма Брайана Гетца на практике из-за его полноты
«Класс является поточно-ориентированным, если он ведет себя правильно при доступе из нескольких потоков, независимо от планирования или чередования выполнения эти потоки в среде выполнения и без дополнительной синхронизации или другой координации со стороны вызывающего кода. "
Просто - код будет работать нормально, если многие потоки исполняют этот код одновременно.
Более информативный вопрос заключается в том, что делает код не потокобезопасным, и ответ заключается в том, что существует четыре условия, которые должны быть выполнены ... Представьте себе следующий код (и его перевод на машинный язык)
totalRequests = totalRequests + 1
MOV EAX, [totalRequests] // load memory for tot Requests into register
INC EAX // update register
MOV [totalRequests], EAX // store updated value back to memory
Потокобезопасный код - это код, который будет работать, даже если много потоков исполняют его одновременно.
Для завершения других ответов:
Синхронизация вызывает беспокойство только тогда, когда код в вашем методе выполняет одно из двух действий:
Это означает, что переменные, определенные в вашем методе, всегда являются потокобезопасными. Каждый вызов метода имеет свою версию этих переменных. Если метод вызывается другим потоком или тем же потоком, или даже если метод вызывает сам себя (рекурсия), значения этих переменных не разделяются.
Планирование потоков не гарантируется как циклический перебор . Задача может полностью перегружать процессор за счет потоков с одинаковым приоритетом. Вы можете использовать Thread.yield (), чтобы иметь совесть. Вы можете использовать (в Java) Thread.setPriority (Thread.NORM_PRIORITY-1), чтобы понизить приоритет потока
Плюс, остерегайтесь:
Не путайте безопасность потоков с детерминизмом. Потокобезопасный код также может быть недетерминированным. Учитывая сложность отладки проблем с многопоточным кодом, это, вероятно, нормальный случай. : -)
Безопасность потока просто гарантирует, что когда поток изменяет или читает совместно используемые данные, никакой другой поток не может получить к нему доступ таким образом, чтобы изменить данные. Если ваш код зависит от определенного порядка выполнения для правильности, то вам нужны другие механизмы синхронизации, помимо тех, которые требуются для обеспечения безопасности потока.
По сути, многие вещи могут пойти не так в многопоточной среде (переупорядочивание инструкций, частично построенные объекты, одна и та же переменная, имеющая разные значения в разных потоках из-за кэширования на уровне ЦП и т. Д.).
Мне нравится определение, данное в Java Concurrency in Practice :
[Часть кода] является поточно-ориентированной, если она ведет себя правильно при доступе из нескольких потоков, независимо от того, планирования или чередования выполнения этих потоков средой выполнения и без дополнительной синхронизации или другой координации со стороны вызывающего кода.
Под правильно они подразумевают, что программа ведет себя в соответствии со своими спецификациями.
Придуманный пример
Представьте, что вы реализуете счетчик. Вы могли бы сказать, что он ведет себя правильно, если:
counter.next()
никогда не возвращает значение, которое уже было возвращено ранее (для простоты мы не предполагаем переполнения и т. Д.) Счетчик потока безопасности будет вести себя в соответствии с этими правилами независимо от того, сколько потоков обращается к нему одновременно (что обычно не будет случай наивной реализации).
Примечание: кросс-пост на программистов
Да и нет.
Безопасность потоков - это нечто большее, чем просто обеспечение доступа к вашим общим данным только одним потоком за раз. Вы должны обеспечить последовательный доступ к общим данным, в то же время избегая условий гонки , взаимоблокировок , живых блокировок и истощения ресурсов . .
Непредсказуемые результаты при работе нескольких потоков не являются обязательным условием потокобезопасного кода, но часто являются побочным продуктом. Например, у вас может быть схема производитель-потребитель , настроенная с общей очередью, одним потоком производителя и несколькими потоками-потребителями, и поток данных может быть совершенно предсказуемым. Если вы начнете представлять больше потребителей, вы увидите больше случайных результатов.
По крайней мере, в C++, я думаю ориентированный на многопотоковое исполнение как что-то вроде неправильного употребления, в котором он упускает много из имени. Чтобы быть ориентированным на многопотоковое исполнение, код обычно должен быть превентивный об этом. Это обычно не пассивное качество.
, Чтобы класс был безопасен от шага, он должен иметь "дополнительные" функции, которые добавляют наверху. Этими функциями является часть реализации класса и вообще говоря, скрытые от интерфейса. Таким образом, различные потоки могут получить доступ к любому из участников класса, никогда не имея необходимость волноваться о конфликте с параллельным доступом другим потоком И могут сделать так очень ленивым способом, с помощью простого регулярного человеческого стиля кодирования, не имея необходимость делать весь этот сумасшедший материал синхронизации, который уже прокручивается в кишки называемого кода.
И это - то, почему некоторые люди предпочитают использовать термин , внутренне синхронизировался .
существуют три основных набора терминологии для этих идей, с которыми я встретился. Первое и исторически более популярный (но хуже):
второе (и лучше):
, одна треть:
ориентированный на многопотоковое исполнение ~ доказательство потока , ~ внутренне синхронизировался
, пример внутренне синхронизировался (иначе. ориентированный на многопотоковое исполнение или доказательство потока ) система является рестораном, где хост приветствует Вас у двери и запрещает Вам от организации очередей самим. Хост является частью механизма ресторана для контакта с несколькими клиентами и может использовать некоторые довольно хитрые приемы для оптимизации размещения ожидающих клиентов, как принятие во внимание размера их стороны, или на какое количество времени они похожи, они имеют, или даже взятие резервирования по телефону. Ресторан внутренне синхронизируется, потому что все это - часть интерфейса для взаимодействия с ним.
не ориентированный на многопотоковое исполнение (но хороший) ~ распараллеливают совместимый , ~ внешне синхронизировался
предположим, что Вы переходите к банку. Существует строка, т.е. конкуренция для кассиров банка. Поскольку Вы не дикарь, Вы распознаете, что лучшая вещь сделать посреди конкуренции для ресурса состоит в том, чтобы поставить в очередь как цивилизованное существо. Никто технически не заставляет Вас сделать это. Мы надеемся, что у Вас есть необходимое социальное программирование, чтобы сделать это самостоятельно. В этом смысле лобби банка , внешне синхронизировался. мы должны сказать, что это небезопасно потоком? это - то, что - импликация то, если Вы идете с ориентированный на многопотоковое исполнение , небезопасный потоком биполярный набор терминологии. Это не очень хороший набор условий. Лучшая терминология , внешне синхронизировался, Это не враждебно к тому, чтобы быть полученным доступ несколькими клиентами, но это не делает работы синхронизации их также. Клиенты делают это сами.
не ориентированный на многопотоковое исполнение (и плохо) ~ распараллеливают враждебный ~ unsynchronizeable
пример враждебный к потоку , система - при вхождении в отношения с кем-то, кто изменяет Вам, потому что, даже если Вам говорят, у Вас есть эксклюзивный доступ к ним глубоко, это не верно, и доверительный повреждается. Повреждение "данных" включено. Разрешение почти невозможно, потому что система становится не детерминированной, ведя к разбивке значения в межличностном общении, точно так же, как с потоками. Этот шаблон может также считаться более широко [1 127] антиобщественный, , который я предпочитаю, потому что это менее характерно для потоков и так в более общем плане применимо ко многим областям программирования.
, первому и самому старому набору терминологии не удается сделать более прекрасное различие между [1 129] враждебность потока и совместимость потока . Совместимость потока более пассивна, чем так называемая потокобезопасность, но это не означает, что названный код небезопасен для параллельного использования потока. Это просто означает, что это пассивно о синхронизации, которая позволила бы это, отложив его к коду вызова, вместо если он как часть его внутренней реализации. Поток, совместимый , - то, как код должен, вероятно, быть написан по умолчанию в большинстве случаев, но это также печально ошибочно думается, поскольку распараллеливают небезопасный, , как будто он по сути выступает против безопасности, которая является важным пунктом беспорядка для программистов.
По существу, наша цель состоит в том, чтобы ниспровергать хаос.
Мы делаем это путем создания детерминированных систем, на которые мы можем полагаться. Детерминизм является дорогим, главным образом из-за альтернативных издержек проигрывающих вещей как параллелизм, конвейерная обработка и переупорядочение. Мы пытаемся минимизировать сумму детерминизма, который мы должны поддержать нашими затратами на низком уровне, также избегая принятия решений, которые далее разрушат то, что мало детерминизма мы можем предоставить.
Синхронизация потоков об увеличении порядка и уменьшении хаоса. Уровни, на которых Вы делаете это, соответствуют упомянутым выше условиям. Высший уровень означает, что система ведет себя совершенно предсказуемым способом каждый раз. Второй уровень означает, что система ведет себя достаточно хорошо, что код вызова может надежно обнаружить непредсказуемость. Например, побочный пробуждение в условной переменной или отказе заблокировать взаимное исключение, потому что это не готово. Третий уровень означает, что система не ведет себя достаточно хорошо для проигрывания с кем-либо еще и может только КОГДА-ЛИБО выполняться однопоточная, не подвергаясь хаосу.