Что такое api

Как определить клиентоориентирован ли бизнес

Чем довольнее клиент на каждом этапе путешествия с вашим брендом (Customer Journey Map), тем выше клиентоориентированность. Для каждого бизнеса карта путешествия клиента уникальна, но можно выделить пять базовых элементов.

Признаки клиентоориентированной компании

Позиционирование и реклама

  • Ценности компании резонируют с ценностями целевой аудитории.
  • Главное сообщение — на языке клиентов.

Сайт

  • Сайтом удобно пользоваться: легко найти нужный раздел и понять подсказки.
  • Можно купить в один клик.
  • Есть раздел с ответами на популярные вопросы.
  • Легко найти контакты для связи.

Продукт

  • Отвечает запросам пользователей. Его создают, опираясь на исследования потребностей и желаний потенциальный клиентов.
  • Материалы — безопасные и экологичные.
  • Предвосхищает ожидания.

Поддержка

  • Клиент быстро получает обратную связь.
  • С сотрудниками компании можно связаться несколькими способами.
  • Консультанты общаются на языке клиента.

Логистика

  • Быстрая доставка.
  • Если доставку задерживают, клиенту дают бонусы.
  • Передвижение товара можно отследить в реальном времени.

Почему важно знать причины неоплаты?

Оплата банковской картой через интернет — эту услугу сейчас предлагает практически любой интернет магазин. Вы можете например купить билет на поезд, оплатив банковской картой, сделать покупку на ozon.ru, купить ЖД билет онлайн.

Я всегда заказывал и оплачивал билеты банковской картой через интернет(я использую только дебетовые карты, у меня нет кредитной карты). Самое интересное, что и эта услуга иногда дает сбой — зависают деньги на карте, не проходит оплата.

Но у меня был случай, когда оплата просто не проходила. Робокасса писала сообщение — оплата отменена. Я не знал, в чем причина. В личном кабинете найти ошибку мне не удалось.
Существует множество разных причин ошибок — они бывают по причине банка или владельца карты

Важно хотя бы предполагать причину ошибки, чтоб понимать как действовать дальше? К примеру, если не удается оплатить горячий билет, то нужно понимать в чем причина и попытаться исправить проблему. Иначе билет может быть куплен другим человеком

Пайпы & операторы

Pipe — это метод класса Observable, добавленный в RxJS в версии 5.5. Благодаря ему мы можем строить цепочки операторов для последовательной обработки значений, полученных в потоке. Pipe представляет собой однонаправленный канал, который связывает между собой операторы. Сами операторы являются обычными функциями, описанными в RxJS, которые обрабатывают значения из потока.

Например, они могут преобразовать значение и передать его дальше в поток, или могут выполнять роль фильтров и не пропускать какие-либо значения, если они не соответствуют заданному условию.

Посмотрим на операторы в деле. Умножим каждое значение из потока на 2 с помощью оператора map:

of(1,2,3).pipe(  map(value => value * 2)).subscribe({  next: console.log});

Вот как выглядит поток до применения оператора map:

После оператора map:

Давайте воспользуемся оператором filter. Этот оператор работает точно так же, как функция filter в классе Array. Первым аргументом метод принимает функцию, в которой описано какое-либо условие. Если значение из потока удовлетворяет условию, то оно пропускается дальше:

of(1, 2, 3).pipe(  // пропускаем только нечетные значения  filter(value => value % 2 !== 0),  map(value = value * 2)).subscribe({  next: console.log});

И вот как будет выглядеть вся схема нашего потока:

После filter:

После map:

Зачем использовать Postman?

Сегодня Postman — супер-популярный инструмент. Им пользуются более 8 миллионов разработчиков и тестировщиков. И вот почему:

  • Бесплатный. Postman — бесплатный инструмент.
  • Простой в использовании. Очень просто начать пользоваться — Postman интуитивно понятный. Уже через несколько минут после скачивания и установки вы сможете отправить ваш первый запрос.
  • Поддерживает разные API. С помощью Postman можно выполнять разные типы запросов к любым API (REST, SOAP, GraphQL (по тестированию GraphQL c помощью Postman у нас есть отдельная статья)
  • Расширяемый. Postman можно настроить под ваши конкретные нужды с помощью Postman API.
  • Интегрируемый. Можно легко интегрировать наборы тестов в ваш любимый CI/CD инструмент с помощью Newman (CLI collection runner — позволяет запускать Postman-коллекции в командной строке)
  • Имеет большое комьюнити. Postman очень популярный и, как следствие, имеет большое комьюнити, которое подскажет ответы на большинство вопросов.

4 Объясните следующие термины: монитор мьютекс критическая секция

Монитор, мьютекс (mutex) – это средство обеспечения контроля за доступом к ресурсу.
У монитора может быть максимум один владелец в каждый текущий момент времени.
Следовательно, если кто-то использует ресурс и захватил монитор для обеспечения единоличного доступа, то другой,
желающий использовать тот же ресурс, должен подождать освобождения монитора,
захватить его и только потом начать использовать ресурс.

Удобно представлять монитор как id захватившего его объекта. Если этот id равен 0 – ресурс свободен.
Если не 0 – ресурс занят. Можно встать в очередь и ждать его освобождения.

В Java у каждого экземпляра объекта есть монитор, который контролируется непосредственно виртуальной машиной.
Используется он так: любой нестатический synchronized-метод при своем вызове прежде всего пытается захватить монитор того объекта,
у которого он вызван (на который он может сослаться как на this). Если это удалось – метод исполняется.
Если нет – поток останавливается и ждет, пока монитор будет отпущен.

Монитор — это дополнительная «надстройка» над мьютексом. По сути, монитор в Java выражен с помощью слова synchronized

Пример на практике

Вот пример использования ввода/вывода данных со стандартными потоками:

#include <iostream>
#include <cstdlib> // для exit()

int main()
{
// Сначала мы используем оператор вставки с объектом cout для вывода текста на монитор
std::cout << «Enter your age: » << std::endl;

// Затем мы используем оператор извлечения с объектом cin для получения пользовательского ввода
int nAge;
std::cin >> nAge;

if (nAge <= 0)
{
// В этом случае мы используем оператор вставки с объектом cerr для вывода сообщения об ошибке
std::cerr << «Oops, you entered an invalid age!» << std::endl;
exit(1);
}

// А здесь мы используем оператор вставки с объектом cout для вывода результата
std::cout << «You entered » << nAge << » years old» << std::endl;

return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#include <iostream>
#include <cstdlib> // для exit()

intmain()

{

// Сначала мы используем оператор вставки с объектом cout для вывода текста на монитор

std::cout<<«Enter your age: «<<std::endl;

// Затем мы используем оператор извлечения с объектом cin для получения пользовательского ввода

intnAge;

std::cin>>nAge;

if(nAge<=)

{

// В этом случае мы используем оператор вставки с объектом cerr для вывода сообщения об ошибке

std::cerr<<«Oops, you entered an invalid age!»<<std::endl;

exit(1);

}

// А здесь мы используем оператор вставки с объектом cout для вывода результата

std::cout<<«You entered «<<nAge<<» years old»<<std::endl;

return;

}

На следующих уроках мы детально рассмотрим функционал потоков ввода/вывода.

Волокна и планирование пользовательского режима

Потоки выполняются на центральном процессоре, а за их переключение отвечает планировщик ядра. В связи с тем что такое переключение это затратная операция. В Windows придумали два механизма для сокращения таких затрат: волокна (fibers) и планирование пользовательского режима (UMS, User Mode Scheduling).

Во-первых, поток с помощью специальной функции может превратится в волокно, затем это волокно может породить другие волокна, таким образом образуется группа волокон. Волокна не видимы для ядра и не обращаются к планировщику. Вместо этого они сами договариваются в какой последовательности они будут обращаться к процессору. Но волокна плохо реализованы в Windows, большинство библиотек ничего не знает о существовании волокон. Поэтому волокна могут обрабатываться как потоки и начнутся различные сбои в программе если она использует такие библиотеки.

Потоки UMS (User Mode Scheduling), доступные только в 64-разрядных версиях Windows, предоставляют все основные преимущества волокон при минимуме их недостатков. Потоки UMS обладают собственным состоянием ядра, поэтому они «видимы» для ядра, что позволяет нескольким потокам UMS совместно использовать процессор и конкурировать за него. Работает это следующим образом:

  • Когда двум и более потокам UMS требуется выполнить работу в пользовательском режиме, они сами могут периодически уступать управление другому потоку в пользовательском режиме, не обращаясь к планировщику. Ядро при этом думает что продолжает работать один поток.
  • Когда потоку UMS все таки нужно обратиться к ядру, он переключается на специально выделенный поток режима ядра.

2. Получение результатов из потоков

Фоновые задачи, созданные с использованием интерфейса , не могут возвращать результаты напрямую. Если вы хотите получать результаты от своих потоков, вы должны использовать вместо этого интерфейс , который также является интерфейсом SAM.

Когда вы передаете объект методу службы executor, вы получаете объект . Как следует из его названия, объект будет содержать результат в какой-то момент в будущем, когда служба исполнителя закончит его запуск. Чтобы получить реальный результат от объекта , все, что вам нужно сделать, это вызвать его метод , но будьте осторожны, ваш поток заблокируется, если вы вызовете его преждевременно.

В следующем примере кода показано, как создать объект , который возвращает типа , запустить его и распечатать его результат:

Что такое клиентоориентированность

Клиентоориентированность — это умение вовремя определить потребности и желания клиентов, чтобы удовлетворить их с максимальной пользой. В идеале — превзойти ожидания и вызвать восторг.

Это альтернатива продуктовым подходам «Продать можно все» и «Хороший товар найдет покупателя». Опираясь на них, компания сначала создает продукт, а уже потом думает, кому его продать, чтобы увеличить продажи. В клиентоориентированном подходе стартовая точка размышлений — желания клиента.

Перевернуть маркетинговую логику предложил экономист Питер Друкер . «Клиент определяет бизнес», — писал он в книге «Практика менеджмента» еще в 1954 году

Не так важно, что компания считает ценностью товара, главное — за что платит клиент. Предназначение бизнеса — соответствовать его запросам

«Наша задача — дать вам то, что удовлетворит желания, о которых вы не подозревали. После чего представить свою жизнь без этого станет невозможно», — CEO Apple Тим Кук .

Владельцам бизнеса бывает трудно провести грань между клиентоориентированностью и выполнением «хотелок» клиента. Главное правило — не нужно ориентировать бизнес на чужих клиентов. Различить здоровую и патологическую клиентоориентированность поможет вопрос: «Кто не наш клиент?» Например, бренду люксовой парфюмерии не стоит реагировать на просьбы провести розыгрыш продукта за репост в соцсетях, а веганскому ресторану — расширять ассортимент по просьбе любителей мяса.

Клиент всегда прав, если это ваш клиент. Нужно исполнять желания тех, кто четко подпадает под целевую аудиторию и, вероятно, принесет прибыль в долгосрочной перспективе.

Согласно статистике Gartner , 80% прибыли компании генерирует 20% клиентов — на них и стоит сконцентрироваться. Угождать им выгодно — по данным консалтинговой компании Invesp , привлечение новых клиентов обходится в пять раз дороже, чем удержание старых. А сохранение 5% клиентов может увеличить прибыль до 95%.

Индустрия 4.0

Глава Apple Тим Кук: «Вы больше не клиент. Вы — продукт»

Клиентоориентированными могут быть не только бизнесы, но и люди. Это один из самых важных гибких навыков (soft skills). Просто перенесите принципы подхода на свои отношения коллегами, работодателями, друзьями и знакомыми.

Например, если меняете работу, проанализируйте свою целевую аудиторию. Это будут HR, руководители отделов и директора. Подумайте, какие проблемы с соискателями у них бывают, как вы можете их решить. Изучайте аудитории разных сфер вашей жизни, помогайте удовлетворять запросы и закрывать проблемы этих людей.

Создаём свою реализацию метода Object.create

В этом посте мы в значительной степени уделяли внимание созданию объектов с использованием метода , который делегирует прототипу функции-конструктора. На этом этапе вы должны знать как использовать метод внутри своего кода, но есть еще одна деталь, о которой вы, вероятно, еще не задумывались

Это как на самом деле метод работает, как говорится, под капотом. И чтобы вам стало это понятно, мы собираемся воссоздать всю его функциональность, воспользуюсь более простыми средствами языка.

И так, что мы уже знаем о работе метода ?

  1. Он принимает аргумент, который должен быть объектом.
  2. Он создает объект, который делегирует объекту аргумента при неудачных поисках свойств и методов в экземпляре объекта.
  3. Возвращает новый созданный объект.

Давайте начнем с пункта #1.

Object.create = function (objToDelegateTo) {

}

Это достаточно просто.

Теперь по пункту #2 — нам нужно создать объект, который будет делегировать объекту, передаваемому через аргумент, при неудачных поисках его свойств. Это немного сложнее. Для этого мы используем наши знания о том, как работает ключевое слово и прототипы в JavaScript. Во-первых, внутри кода нашей реализации аналога метода мы создадим пустую функцию . Затем присвоим ей в качестве прототипа объект, переданный из аргумента. Далее создадим новый объект, то есть вызовем нашу пустую функцию с использованием ключевого слова .

Теперь нам остается, используя оператор , возвратить из функции вновь созданный объект — пункт #3 тоже выполнен. Что же у нас получилось, смотрим код ниже:

Object.create = function (objToDelegateTo) {
  function Fn(){}
  Fn.prototype = objToDelegateTo
  return new Fn()
}

Необычно? Давайте пройдемся по нему.

Вначале мы создаем новую функцию , которая получает новое значение для своего свойства . Когда мы вызываем её с помощью ключевого слова , мы знаем, что получаем объект, который далее будет делегировать прототипу функции при неудачных поисках её свойств. Таким образом, если мы переопределим прототип функции, то сможем самостоятельно определять, какому объекту делегировать при неудачных поисках. Иначе говоря мы перезаписываем прототип функции объектом , который передаем в качестве аргумента при вызове нашего аналога .

12 Назовите отличия synchronize{} и ReentrantLock

В Java 5 появился интерфейс Lock предоставляющий возможности более эффективного и тонкого контроля блокировки ресурсов.
ReentrantLock – распространённая реализация Lock, которая предоставляет Lock с таким же базовым поведением и семантикой,
как у synchronized, но расширенными возможностями, такими как опрос о блокировании (lock polling),
ожидание блокирования заданной длительности и прерываемое ожидание блокировки.
Кроме того, он предлагает гораздо более высокую эффективность функционирования в условиях жесткой состязательности.

Что понимается под блокировкой с повторным входом (reentrant)? Просто то, что есть подсчет сбора данных, связанный с блокировкой,
и если поток, который удерживает блокировку, снова ее получает, данные отражают увеличение,
и тогда для реального разблокирования нужно два раза снять блокировку. Это аналогично семантике synchronized;
если поток входит в синхронный блок, защищенный монитором, который уже принадлежит потоку, потоку будет разрешено
дальнейшее функционирование, и блокировка не будет снята, когда поток выйдет из второго (или последующего) блока synchronized,
она будет снята только когда он выйдет из первого блока synchronized, в который он вошел под защитой монитора.

Lock lock = new ReentrantLock();

lock.lock();
try { 
  // update object state
}
finally {
  lock.unlock(); 
}

Реализация ReentrantLock гораздо более масштабируема в условиях состязательности, чем реализация synchronized.
Это значит, что когда много потоков соперничают за право получения блокировки,
общая пропускная способность обычно лучше у ReentrantLock, чем у synchronized.
JVM требуется меньше времени на установление очередности потоков и больше времени на непосредственно выполнение.
У ReentrantLock (как и у других реализаций Lock) блокировка должна обязательно сниматься в finally блоке
(иначе, если бы защищенный код выбросил исключение, блокировка не была бы снята).
Используя синхронизацию, JVM гарантирует, что блокировка автоматически снимаются.
Резюмируя можно сказать, что когда состязания за блокировку нет либо оно очень мало, то synchronized возможно будет быстрее.
Если присутствует заметное состязание за доступ к ресурсу, то скорее всего ReentrantLock даст некое преимущество.

Особенности Postman

Ниже мы перечислим только некоторые из особенностей Postman:

  • Простой в использовании API клиент
  • Функциональный и приятный UI.
  • Может использоваться как для ручного, так и для автоматизированного тестирования API.
  • Поддерживает интеграции с другими инструментами (например, поддерживает Swagger и RAML)
  • Может быть запущен в Windows, Linux, MacOS.
  • Не требует знания языков программирования.
  • Предоставляет возможность легко экспортировать коллекции запросов, наборы тестов. Можно легко обмениваться этими данными с коллегами.
  • Интегрируется с CI/CD инструментами (например, с Jenkins, TeamCity и т.п.)
  • API Posman-a подробно документирован.
  • Позволяет выполнять API автотесты.

Больше информации о Postman можно найти на официальном сайте: https://www.getpostman.com/

Postman — freemium-интсрумент. Но бесплатной версии более, чем достаточно, чтобы проводить базовое тестирование API.

std::atexit

Поскольку завершает программу немедленно, вы можете перед завершением выполнить какую-либо очистку вручную (в приведенном выше примере мы вручную вызывали функцию ). Поэтому программисту необходимо не забывать вручную вызывать функцию очистки перед каждым вызовом .

Чтобы помочь в этом, C++ предлагает функцию , которая позволяет вам указать функцию, которая будет автоматически вызываться при завершении программы через .

Эта программа имеет тот же вывод, что и предыдущий пример:

Так зачем вам это делать? Это позволяет вам указать функцию очистки в одном месте (возможно, в ), а затем не беспокоиться о том, чтобы не забыть вызвать эту функцию явно перед вызовом .

Несколько замечаний о и функции очистки: во-первых, поскольку вызывается неявно при завершении , если программа завершается таким образом, это вызовет любые функции, зарегистрированные . Во-вторых, регистрируемая функция не должна принимать никаких параметров и должна не иметь возвращаемого значения. Наконец, с помощью вы можете зарегистрировать несколько функций очистки, если хотите, и они будут вызываться в порядке, обратном порядку регистрации (последняя зарегистрированная будет вызываться первой).

Для продвинутых читателей

В многопоточных программах вызов может привести к сбою вашей программы (поскольку поток, вызывающий , будет очищать статические объекты, к которым могут обращаться другие потоки). По этой причине в C++ появилась еще одна пара функций, которые работают аналогично и , – и . завершает программу нормально, но не очищает статические объекты и может выполнять или не выполнять другие типы очистки. выполняет ту же роль, что и для программ, завершаемых с помощью .

Основные сущности Postman: запросы, коллекции и окружения

Перед тем, как приступить непосредственно к тестированию, давайте рассмотрим основные сущности, которыми оперирует Postman:

  1. Запросы
  2. Коллекции
  3. Окружения

1. Запросы (Requests)

Запрос представляет собой комбинацию URL, хедеров и Body (тела запроса). Postman позволяет сохранять запросы и использовать их в будущем там, где вам нужно.

Чтобы создать новый запрос, нажмите New — Request

Как мы писали выше, Postman позволяет делать запросы к API. С помощью API-запроса можно получать и отправлять данные какому-либо бэкенд-сервису.

Для каждого API-запроса нужно выбрать HTTP-method.

Что такое HTTP?

HTTP — сокращение от HyperText Transfer Protocol (протокол передачи гипертекста). Протокол используется для общения клиента и сервера. Клиентом, к примеру, может быть браузер (в нашей статье в качестве клиента используется Postman).

После отправки клиентом HTTP-запроса, сервер возвращает ответ. Ответ сервера содержит метаданные о статусе и запрашиваемый контент.

Наиболее распространенные типы HTTP-запросов:

  1. GET: GET-запросы используются для получения данных от API.
  2. POST: POST-запросы используются для отправки новых данных API.
  3. PUT: PUT-запросы используются для обновления уже существующих данных.
  4. PATCH: PATCH-запросы (как и PUT) используются для обновления уже существующих данных. Разница в том, что с помощью PATCH запросов можно обновить несколько записей за раз.
  5. DELTE: DELETE-запросы используются для удаления существующих данных.

Далее в статье мы рассмотрим, как создавать и отправлять запросы разных типов с помощью Postman.

2. Коллекции (Collections)

Коллекции представляют собой группы запросов. Вы можете думать о коллекциях как о папках, в которых лежат запросы.

Как создать коллекцию в Postman:

Нажмите New — Collection

Введите имя (Name) и описание (Description) коллекции, после этого нажмите кнопку Create:

Коллекция может содержать любое число запросов. Запустить выполнение коллекции можно двумя способами:

  1. с помощью Collection Runner
  2. c помощью Newman

Далее мы рассмотрим оба этих способа.

3. Окружение (Environments)

Окружения в Postman позволяют запускать запросы и коллекции, используя разные наборы данных. Например, мы можем создавать разные окружения в Postman для Dev, QA и Production серверов. В каждом из окружений будут свои собственные настройки: например, URL, auth token-ы и пароли, API-ключи и т.п. Окружения представляют собой наборы пар «ключ-значение».

Чтобы создать новое окружение (Environment), нажмите New — Environment

Мы рассмотрим работу с окружениями далее в статье.

Создание тестов в Postman

Тесты в Postman позволяют убедиться, что API работает так, как этого от него ожидают.

Давайте начнем с написания простого теста.

Шаг 1: Возвращаемся к GET-запросу, который мы создали ранее и переключаемся во вкладку Tests (Тесты). В секции сниппетов нажимаем на сниппет «Status code: Code is 200». В окне теста появится скрипт. Этот скрипт будет проверять, что запрос возвращает код ответа 200.

Шаг 2: Нажмите кнопку Send (Отправить). В нижней части окна вы увидите результат выполнения теста (в нашем случае он выполнился успешно).

Шаг 3: Давайте добавим еще один тест. В этот тесте мы будем сравнивать полученный результат с ожидаемым. Чтобы это сделать, выбираем сниппет с названием «Response body:JSON value check». Давайте проверим, что пользователь с именем Leanne Graham имеет userid 1.

Шаг 4: Заменим название теста на что-то более понятное: вместо «Your test name» напишем «Check if Leanne Graham has the userid 1». Также заменим на (т.к. jsonData представляет собой массив, а массивы начинаются с 0):

Код теста будет выглядеть следующим образом:

pm.test("Check if user with id1 is Leanne Graham", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.name).to.eql("Leanne Graham");
});

Шаг 5: Нажимаем Send (Отправить)

Сборка мусора

Обычно лексическое окружение очищается и удаляется после того, как функция выполнилась. Например:

Здесь два значения, которые технически являются свойствами лексического окружения. Но после того, как завершится, это лексическое окружение станет недоступно, поэтому оно удалится из памяти.

…Но, если есть вложенная функция, которая всё ещё доступна после выполнения , то у неё есть свойство , которое ссылается на внешнее лексическое окружение, тем самым оставляя его достижимым, «живым»:

Обратите внимание, если вызывается несколько раз и возвращаемые функции сохраняются, тогда все соответствующие объекты лексического окружения продолжат держаться в памяти. Вот три такие функции в коде ниже:. Объект лексического окружения умирает, когда становится недоступным (как и любой другой объект)

Другими словами, он существует только до того момента, пока есть хотя бы одна вложенная функция, которая ссылается на него

Объект лексического окружения умирает, когда становится недоступным (как и любой другой объект). Другими словами, он существует только до того момента, пока есть хотя бы одна вложенная функция, которая ссылается на него.

В следующем коде, после того как станет недоступным, лексическое окружение функции (и, соответственно, ) будет удалено из памяти;

Как мы видели, в теории, пока функция жива, все внешние переменные тоже сохраняются.

Но на практике движки JavaScript пытаются это оптимизировать. Они анализируют использование переменных и, если легко по коду понять, что внешняя переменная не используется – она удаляется.

Одним из важных побочных эффектов в V8 (Chrome, Opera) является то, что такая переменная становится недоступной при отладке.

Попробуйте запустить следующий пример в Chrome с открытой Developer Tools.

Когда код будет поставлен на паузу, напишите в консоли .

Как вы можете видеть – такой переменной не существует! В теории, она должна быть доступна, но попала под оптимизацию движка.

Это может приводить к забавным (если удаётся решить быстро) проблемам при отладке. Одна из них – мы можем увидеть не ту внешнюю переменную при совпадающих названиях:

До встречи!

Эту особенность V8 полезно знать. Если вы занимаетесь отладкой в Chrome/Opera, рано или поздно вы с ней встретитесь.

Это не баг в отладчике, а скорее особенность V8. Возможно со временем это изменится.
Вы всегда можете проверить это, запустив пример на этой странице.

6 Что такое DeadLock Приведите примеры

Взаимная блокировка (deadlock) — явление при котором все потоки находятся в режиме ожидания. Происходит, когда достигаются состояния:

Взаимная блокировка порядка синхронизации

public void transferMoney(Account fromAccount, Account toAccount, Amount amount) throws InsufficientFundsException {
	synchronized (fromAccount) {
		synchronized (toAccount) {
			if (fromAccount.getBalance().compareTo(amount) < )
				throw new InsufficientFundsException();
			else {
				fromAccount.debit(amount);
				toAccount.credit(amount);
			}
		}
	}
}

Данная блокировка вызвана тем, что синхронизация счетов может происходить в разном порядке.
Соответственно, если ввести некоторый порядок на счетах (это некоторое правило, позволяющее сказать, что счет A меньше чем счет B), то проблема будет устранена.

Взаимная блокировка между объектами.

class Plane {
	private Point location, destination;
	private final Dispatcher dispatcher;

	public Plane(Dispatcher dispatcher) {
		this.dispatcher = dispatcher;
	}
	public synchronized Point getLocation() {
		return location;
	}
	public synchronized void setLocation(Point location) {
		this.location = location;
		if (location.equals(destination))
		dispatcher.requestLanding(this);
	}
}

class Dispatcher {
	private final Set<Plane> planes;
	private final Set<Plane> planesPendingLanding;

	public Dispatcher() {
		planes = new HashSet<Plane>();
		planesPendingLanding = new HashSet<Plane>();
	}
	public synchronized void requestLanding(Plane plane) {
		planesPendingLanding.add(plane);
	}
	public synchronized Image getMap() {
		Image image = new Image();
		for (Plane plane  planes)
			image.drawMarker(plane.getLocation());
		return image;
	}
}

В результате, если самолет прибывает на место, в тот же момент, как кто-то решает получить карту может возникнуть взаимная блокировка.
То есть, будут вызваны методы, getMap и setLocation, которые займут мониторы экземпляров Dispatcher и Plane соответственно.
Затем метод getMap вызовет plane.getLocation (в частности для экземпляра Plane, который в данный момент занят),
который будет ждать освобождения монитора для каждого из экземпляров Plane.
В то же время в методе setLocation будет вызван dispatcher.requestLanding, при этом монитор экземпляра Dispatcher остается занят рисованием карты.
Результат – взаимная блокировка.

Ресурсная взаимная блокировка.
Безусловно, если код написан без каких-либо ошибок (примеры которых мы видели в предыдущих разделах),
то взаимных блокировок в нем не будет. Но кто может поручиться, что его код написан без ошибок?
Безусловно, тестирование помогает выявить значительную часть ошибок, но как мы уже видели ранее,
ошибки в многопоточном коде нелегко диагностировать и даже после тестирования нельзя быть уверенным в отсутствии ситуаций взаимных блокировок.
Можем ли мы как-то перестраховаться от блокировок? Ответ – да. Подобные техники применяются в движках баз данных,
которым нередко необходимо восстанавливаться после взаимных блокировок (связанных с механизмом транзакций в БД).

Интерфейс Lock и его реализации доступные в пакете java.util.concurrent.locks позволяют попытаться занять монитор,
связанный с экземпляром данного класса методом tryLock (возвращает true, если удалось занять монитор).
Пусть у нас есть пара объектов реализующих интерфейс Lock и нам необходимо занять их мониторы так, чтоб избежать взаимной блокировки.

Простейший способ избежать взаимной блокировки – не допускать цикличного ожидания. Этого можно достичь,
получая мониторы разделяемых ресурсов в определённом порядке и освобождая их в обратном порядке.

Использование DiffUtil в любом адаптере RecyclerView

Хотя ListAdapterрекомендован RecyclerView.Adapter для использования с DiffUtil, его можно использовать с любым адаптером. Разница в том, что необходимо объявить переменную, которая содержит DiffCallbackи соответствующие currentList и submitListдля доступа и редактирования списка, которой не существует в других адаптерах.

В качестве упражнения откройте MainAdapter.kt, измените объявление класса, чтобы расширить RecyclerView.Adapterи реализовать AsyncListDiffer.

Для начала измените ListAdapter на RecyclerView.Adapter:

Импортируйте androidx.recyclerview.widget.AsyncListDiffer.

После данного изменения DiffCallback больше не устанавливается, и, поскольку currentList — это свойство ListAdapter, оно больше не доступно.

Теперь объявите AsyncListDifferвместе с созданным ранее DiffCallback:

Это поле содержит список адаптеров. Для доступа к нему посредством onBindViewHolder, вызовите:

В getItem, в конце класса адаптера, измените getItem(adapterPosition).timeStampна:

При сборке проекта отображаются все ссылки, требующие обновления. Чтобы упростить преобразование существующего проекта в AsyncListDiffer, создайте следующие методы:

Имена этих методов аналогичны тем, которые вы вызывали ранее, поэтому изменения будут минимальными.

Теперь обновите вызовы для currentList:

Это изменение является обязательным, поскольку теперь оно относится к методу, а не к полю.

Соберите и запустите проект. Добавьте и удалите пару элементов из списка.

Использование Payloads

Вы можете использовать полезные данные (payloads), когда ячейки списка содержат несколько вью и когда обновление одного элемента не требует изменения всего вью. Они особенно полезны, когда вы хотите избежать получения одного и того же изображения или выполнения сложных вычислений.

Сначала откройте MainAdapter.kt. Перед объявлением класса добавьте:

Вы можете использовать эту функцию для определения изменения done из Item и соответствующего изменения и обновление списка.

Перейдите к DiffCallbackи переопределите getChangePayload:

Импортируйте android.os.Bundle.

Обратите внимание, что getChangePayload — это не абстрактный метод. Этот метод вызывается, когда areItemsTheSameвозвращает true и areContentsTheSameвозвращает false. Это указывает на то, что некоторые поля Item изменились

Тем не менее, рекомендуется сравнивать idэлементов, чтобы гарантировать, что это один и тот же элемент.

В этом случае изменения полы относятся к done, поэтому, если его состояние отлично, Bundleвозвращается с измененной информацией.

Перейдите к ItemViewHolderи добавьте update:

Обновлены только те вью, которые используют done. Это позволяет избежать траты ресурсов на обновление полей, которые не изменились.

В этом примере MainAdapterрасширяет ListAdapter. Если вы используете RecyclerView.Adapter, внесите соответствующие изменения.

Обратитесь к onBindViewHolder, добавьте onBindViewHolder, чтобы получить payload в качестве аргумента и обновить существующий:

Вот пошаговое объяснение этой логики:

  1. onBindViewHolder должен быть переопределен. Вот почему вам нужно добавить второй, который содержится в payload в качестве аргумента. Первый метод вызывает второй с аргументом полезной нагрузки, заданным как emptyList().
  2. Вызовите этот метод, если нет изменений с 1 или если есть разница в DiffCallback, рассчитанном в getChangePayload.
  3. Если список payloadпуст, значит, объект новый и вью необходимо отрисовать.
  4. Если payloadсодержит какие-то данные, это означает, что произошло обновление этого объекта. Вы можете повторно использовать некоторые из его вью.

Соберите и запустите проект. Добавьте полезную нагрузку, перейдите к списку покупок и отметьте некоторые предметы.

А вот и рецепт печенья! :]

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: