Синхронизированные ключевые слова
Когда ключевое слово Java Language используется для изменения метода или кодового блока, оно может убедиться, что в максимум максимум один поток выполняет код одновременно.
Когда два параллельных потока получают доступ к этому синхронизированному (этому) синхронизированному кодовому блоку в одном и том же объекте объект, в течение одного времени можно выполнить только один поток. Другой поток должен ждать, пока текущий поток выполнит этот кодовый блок, прежде чем он сможет выполнить кодовый блок.
Однако, когда один поток обращается к одному синхронизированному (этой) кодовому блоку синхронизации объекта, другой поток все еще может получить доступ к несинхронизированному (это) блоку синхронизации в этом объекте.
Особенно важно, чтобы, когда поток обращается к синхронизированному (это) кодовому блоку синхронизации объекта, другие потоки будут блокировать доступ ко всем другим блокам синхронизированной (этой) синхронизации в объекте.
Третий пример также относится к другим блокам синхронного кода. То есть, когда поток обращается к синхронизированному (этой) кодовому блоку синхронизации объекта, он получает блокировку объекта этого объекта. В результате другие потоки доступа ко всем частям синхронного кода объекта объекта временно заблокированы.
Приведенные выше правила также применяются к другим блокировкам объектов.
Пример кода
Пакет Test160118; Public Class TestSynchronized {public static void main (string [] args) {sy sy = new sy (0); Sy sy2 = new sy (1); sy.start (); sy2.start (); }} класс sy extends thread {private int flag; статический объект x1 = new Object (); статический объект x2 = new Object (); public sy (int flag) {this.flag = flag; } @Override public void run () {System.out.println (flag); try {if (flag == 0) {synchronized (x1) {System.out.println (flag+"заблокирован x1"); Thread.sleep (1000); синхронизированный (x2) {System.out.println (flag+"Заблокированный x2"); } System.out.println (flag+"Выпуск x1 и x2"); }} if (flag == 1) {synchronized (x2) {System.out.println (flag+"заблокирован x2"); Thread.sleep (1000); Synchronized (x1) {System.out.println (flag+"Заблокированный x1"); } System.out.println (flag+"Выпуск x1 и x2"); }}} catch (прерывание Exception e) {e.printstackTrace (); }}}
Поток потока с потоком блокировки. Принцип реализации
Что может сделать Threadlocal?
Это предложение трудно сказать. Давайте посмотрим на некоторые из трудностей, с которыми сталкиваются в реальном проекте: когда вы называете некоторые методы в соответствии с некоторыми параметрами в проекте, тогда метод вызывает метод, а затем вызовут метод по объектам, эти методы могут использовать некоторые аналогичные параметры, например, A требуют параметров A, B и B и в A. После вызовов B, B требуют параметров B и C в B и B и B. В настоящее время все параметры должны быть переданы B. и так далее. Если есть много методов, параметры станут все больше и больше. Кроме того, когда программа необходимо добавить параметры, вам необходимо добавить параметры в соответствующие методы один за другим. Да, это очень хлопотно. Я считаю, что вы столкнулись с этим. Это также некоторые общие методы обработки для объектно-ориентированного на языке C. Тем не менее, наш простой метод обработки состоит в том, чтобы обернуть его в объект и передать его. Эта проблема может быть решена, добавив атрибуты объекта. Тем не менее, объекты обычно являются значимыми, поэтому иногда простая упаковка объектов добавляет некоторые расширенные не относящиеся к делу атрибуты, чтобы сделать наше определение класса очень странным, поэтому в этих случаях, когда мы структурируем такие сложные программы, мы используем некоторые область, аналогичные областям, чтобы справиться с ними. Имена и использование чаще встречаются. Подобно веб -приложениям, в контексте, сеансе, запросе, запросе и страницах будут прицеры. Threadlocal также может решить эту проблему, но она не очень подходит для решения этой проблемы. Столкнувшись с этими проблемами, это обычно не проходит на ранних стадиях охвата и объекта, и считает, что параметры не будут добавлены. При добавлении параметров я обнаружил, что есть много мест, которые нужно изменить. Чтобы не уничтожить структуру кода, возможно, что слишком много параметров, что снизило читаемость кода метода. Threadlocal добавляется, чтобы справиться с этим. Например, когда один метод вызывает другой метод, вносятся 8 параметров, а один из параметров передается, вызывая nth метод слой по слою. В настоящее время последний метод должен добавить один параметр. Для первого метода естественно стать 9 параметрами, но в настоящее время соответствующие методы будут вовлечены, что делает код раздутым.
Вышеупомянутые нитолокальные являются целью восстановления проблемы потери овец, но это не особенно рекомендуемый способ его использовать. У него также есть некоторые аналогичные методы для его использования, то есть есть много динамических вызовов на уровне структуры, и некоторые протоколы должны быть выполнены в процессе вызова. Хотя мы стараемся быть универсальными, многие расширенные параметры нелегко рассмотреть при определении протокола, и версия также обновляется в любое время. Однако, когда структура расширена, интерфейс также является универсальной и обратной совместимостью. Нам нужно некоторое расширенное содержимое, чтобы быть удобным и простым.
Проще говоря, Threadlocal превращает некоторые сложные расширения системы в простые определения, что делает детали, вовлеченные в связанные параметры очень простыми. Вот наш пример:
В Spring Transaction Manager соединение, полученное источником данных, размещено в потоке. После выполнения программы соединение получается из Threadlocal, а затем выполняются коммит и откат. При использовании необходимо убедиться, что соединение, полученное программой с помощью данных, получается из пружины. Почему такая операция? Поскольку бизнес -код полностью определяется приложением, а структура не может потребовать, чтобы бизнес -код был написан, в противном случае структура потеряет выгоду от того, что не позволяет бизнес -коду управлять соединением. После того, как бизнес -код будет вырезан, пружина не пройдет подключение к области бизнес -кода. Это должно быть спасено в месте. Когда базовый слой проходит через ибатис и пружину. Когда такая структура, как JDBC, получает подключение того же данных, она будет вызоваться, чтобы получить его в соответствии с правилами, согласованными весной. Поскольку процесс выполнения обрабатывается в одном и том же потоке, то же самое соединение получается, чтобы убедиться, что используемое соединение является таким же во время коммита, отката и бизнес -операций, потому что только тот же Connecton может гарантировать транзакции, в противном случае сама база данных не поддерживается.
Фактически, во многих приложениях параллельных программирования Threadlocal играет очень важную роль. Он не добавляет блокировки и легко заключает потоки плавно, не требуя повторного распределения пространства каждый раз, как локальные переменные. Поскольку многие пространства безопасны для резьбы, они могут многократно использовать буферы-потоки.
Как использовать Threadlocal?
Определите нитолокальную переменную в любом подходящем месте в системе, которая может быть определена как публичный статический тип (непосредственно новый объект Threadlocal). Если вы хотите поместить в него данные, используйте Set (Object), используйте операцию get () и используйте remove () при удалении элементов. Другими методами являются непубличные методы и не рекомендуются.
Вот простой пример (фрагмент кода 1):
public Class Threadlocaltest2 {public final Static Threadlocal <string> test_thread_name_local = new Threadlocal <string> (); public final Static Threadlocal <string> test_thread_value_local = new Threadlocal <string> (); public static void main (string [] args) {for (int i = 0; i <100; i ++) {final String name = "thread- [" + i + "]"; конечная строка value = string.valueof (i); new Thread () {public void run () {try {test_thread_name_local.set (name); Test_thread_value_local.set (value); calla (); } наконец {test_thread_name_local.remove (); Test_thread_value_local.remove (); } } } }.начинать(); }} public static void calla () {callb (); } public static void callb () {new Threadlocaltest2 (). Callc (); } public void callc () {calld (); } public void calld () {System.out.println (test_thread_name_local.get () + "/t =/t" + test_thread_value_local.get ()); }}Здесь мы имитируем 100 потоков для доступа к имени и значению соответственно. Значения имени и значения намеренно устанавливаются в середине, чтобы увидеть, есть ли проблема параллелизма. Через вывод мы видим, что выход потока не выводится в порядке, что означает, что он выполняется параллельно, а имя и значение потока могут быть соответствующими. В середине, с помощью нескольких методов, параметры не передаются в фактическом вызове, так как получить соответствующие переменные. Однако в реальных системах они часто пересекают классы. Здесь они смоделированы только в одном классе. На самом деле, классы кросса - тот же результат. Вы можете имитировать их самостоятельно.
Я считаю, что, увидев это, многие программисты очень заинтересованы в принципе нитолокального. Давайте посмотрим, как это сделано. Хотя параметры не передаются, они могут использовать его как локальные переменные. Это действительно довольно волшебно. На самом деле, вы можете сказать, что это метод настройки. Когда вы видите, что имя должно быть связано с потоком, тогда скажем меньше чепухи, давайте посмотрим на его исходный код. Поскольку мы используем наибольший набор, получить и удалить, затем начните с набора:
Метод набора (t obj) - (фрагмент кода 2):
public void set (t value) {Thread t = Thread.currentThread (); Threadlocalmap map = getMap (t); if (map! = null) map.set (это, значение); else createmap (t, value);}Во -первых, текущий поток получается, так же, как и предположение, а затем есть метод GetMap, который проходит в текущем потоке. Сначала мы можем понять, что эта карта - карта, связанная с потоком. Далее, если он не пуст, выполните операцию установки. Когда вы следуете за ним, вы обнаружите, что это похоже на работу HASHMAP, то есть часть данных записывается на карту. Если он пуст, способ CreateMap вызывается. После входа посмотрите (код фрагмент 3):
void createmap (поток t, t firstvalue) {t.threadlocals = new Threadlocalmap (this, firstvalue);}Кэшбэк создает Threadlocalmap и записывает прошедшие параметры и текущие потоки в виде структуры KV (фрагмент кода 4):
Threadlocalmap (Threadlocal FirstKey, Object FirstValue) {table = Новая запись [initial_Capacity]; int i = FirstKey.ThreadlocalhashCode & (initial_capacity - 1); Таблица [i] = Новая запись (FirstKey, FirstValue); размер = 1; setThreshold (initial_capacity);}Это не объяснено здесь структурные детали Threadlocalmap. Вам нужно только знать, что его реализация похожа на HashMap. Существует много методов, которые не имеют карты реализаций, потому что она не хочет, чтобы вы получали карту некоторыми методами (такими как отражение) для дальнейшего ее эксплуатации. Это статический внутренний класс в Threadlocal, тип по умолчанию, и только классы под Java.Lang могут ссылаться на него, так что вы можете придумать поток.
Давайте посмотрим на метод GetMap, потому что я знаю, что полученная карта связана с потоком, и через фрагмент кода 3 есть T.Threadlocalmap = new Threadlocalmap (это, FirstValue), я считаю, что вы, вероятно, должны понимать, что эта переменная должна исходить из потока. Пойдем в соответствии с методом GetMap:
Threadlocalmap getMap (Thread T) {return t.threadlocals;}Да, это происходит из потока, и этот поток оказался текущим потоком, так что идите и посмотрите на определение:
Threadlocal.Threadlocalmap Threadlocals = null;
Это свойство находится в классе потока, то есть в каждом потоке по умолчанию есть Threadlocalmap, который используется для хранения локальных переменных на уровне потока. Обычно вы не можете присвоить ему значения, потому что такие назначения обычно небезопасны.
Это кажется немного грязным, не волнуйтесь, давайте оглянемся назад и рассмотрим идеи:
1. В потоке есть свойство, которое похоже на Hashmap, но его название Threadlocalmap. Это свойство имеет тип по умолчанию, поэтому можно ссылаться на все классы в одном и том же пакете. Поскольку это локальная переменная потока, каждый поток имеет свою отдельную карту, которая не противоречит друг другу, поэтому даже если потоки определяются как статические потоки, конфликта не будет.
2. Threadlocal и Thread находятся под тем же пакетом. Вы можете ссылаться на этот класс и работать на нем. В настоящее время каждый Threadlocal определяет один, используйте это в качестве ключа и значение, которое вы передаете в качестве значения, и это определение Threadlocal, который вы определяете. Следовательно, различные потоковые переменные используют SET SET, и данные между друг другу не будут конфликтуют, потому что их ключи разные. Конечно, после того, как тот же Threadlocal выполняет две установленные операции, в последний раз будет преобладающим.
3. Подводя итог, когда потоки параллельны, можно использовать нитолокальные, такие как локальные переменные, и являются защищенными потоками, а данные между различными нитокальными переменными не имеют конфликта.
Давайте продолжим смотреть на метод получения и удалить метод, он на самом деле просто:
public t get () {Thread t = Thread.currentThread (); Threadlocalmap map = getMap (t); if (map! = null) {threadlocalmap.Entry e = map.getEntry (this); if (e! = null) return (t) e.value; } return setInitialValue ();}Вызывая метод GetMap в соответствии с текущим потоком, то есть t.threadlocalmap вызывается, а затем поиск на карте, обратите внимание, что карта найдена при записи, то есть основная структура KV, поскольку вы пишете только значение, она установит E.value, чтобы вернуть написанное значение, которое вы написали, потому что ключ является самим платформой. Вы можете видеть, что Map.getEntry также получается через это.
Тот же метод удаления:
public void remove () {threadlocalmap m = getMap (thread.currentThread ()); if (m! = null) M.Remove (this);}Кроме того, карта получается на основе текущего потока. Если он не пуст, удалите и удалите через это.
Кроме того (2013-6-29), каковы подводные камни забывания написать? Какие ловушки есть в этом нитолокальном? Из предыдущего примера вы должны увидеть, что объект, связанный с потоком, связан с картой, и эта карта является свойством потока потока. Тогда есть проблема, что если вы не снимаете себя или если вы не знаете, когда удалить в своей собственной программе, то поток не будет вычеркнут, и набор данных в введении не будет вычеркнут.
С другой стороны, если только вы не понимаете, где должен быть установлен этот объект и где удалить. Если это расплывчато, вполне вероятно, что ваш код не перейдет в положение удаления или вызовет некоторые логические проблемы. Кроме того, если он не удален, вам нужно ждать, пока поток будет вычеркнут. Во многих серверах приложений потоки используются повторно, потому что в потоках распределения ядра все еще есть накладные расходы, поэтому в этих приложениях трудно выходить из строя. Затем данные, записанные в Threadlocal, естественно, нелегко выйти из строя. Они могут быть случайно скрыты и использованы, когда мы используем некоторые рамки с открытым исходным кодом, что может вызвать проблемы. Наконец, я обнаружил, что когда OOM данные фактически поступают из Threadlocalmap. Я не знаю, где установлены эти данные, поэтому вы должны обратить внимание на эту яму, и в эту яму попал более одного человека.