Как смотреть страницы входа в процентном соотношение в Яндекс-метрике



1. Заходим в отчет. Стандартные отчеты -> Содержание -> Страницы входа.
2. Потом нажимаем кнопку Группировка. Там убираем все кроме 1 пункта - "Страница входа".
3. Далее в таблице уже нажимаем процент.

Не могли нормально сделать ....


Так можно посмотреть трафик на внутряк. Забавно, что Google Search Console, также как и ahref, показывает те же запросы на внутряк, что и на главную. Но очевидно, тут проблема в том, что в поиске появляется просто быстрые ссылки(Google называет их Sitelinks).  Они и портят картину.

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

В частности внутряк по непонятным причинам ранжируется по бренд-анкорам.

Про PBN от ahrefs


Шикарный пост про PBN - https://ahrefs.com/blog/link-building-services/

И не более шикарный коммент Tommy McDonald, который рассказал как сделал лям баксов за год, перепродавая ссылки с SAPE на форуме BHW (хотя наверное это был какой-то пакет). Забавно, он упомянул, что основные покупатели PBN - это агенства офлайн, которые занимаются сео-продвижением и чарджат по 1к зелени с клиента

Simple mortgage calculator with PMI



Using this free mortgage calculator you can accurately predict your monthly payments. This calculator includes amortization tables, bi-weekly savings estimates, refinance and more


Akamai CDN


Зарегистрировался на Rackspace. Rackspace использует сетку Akamai для раздачи контента. Её же вроде использует Facebook.

Настройка CDN - всё очень быстро и понятно, минут за 15 можно все сделать. Но увы не заработало сразу, сервер в Германии. Открываю контент напрямую 100мсек, открываю через Raskspace - 150мсек.  Расстроился, стал думать, что здесь всё также плохо у Amazon, на всякий случай написал в саппорт. Оказалось, что мой ресурс не кешировался, Akamai шел за CSS файлом на мой сервер каждый раз.

Причиной тому http header, добавляемый Nginx - Vary https://support.rackspace.com/how-to/rackspace-cdn-object-is-not-being-cached/. Несмотря на то, что у них в документации написано, что они закеширует ресурс, если присутвуют оба хидера Vary: Accept-Encoding и Content-Encoding: gzip, в моем случае этого не произошло. Как только убрал Vary совсем, всё заработало.

Саппорт кстати довольно грамотный отвечал аж на выходных в течении 30-40 минут. Чтобы понять произошел hit или miss по кешу, можно использовать эту команду

curl -L -s -o /dev/null -D - -H "Pragma: akamai-x-get-request-id, akamai-x-cache-on, akamai-x-cache-remote-on, akamai-x-check-cacheable, akamai-x-get-cache-key, akamai-x-get-extracted-values, akamai-x-get-true-cache-key"  https://yourdomain,scdn2.secure.raxcdn.com/main.css


Обратить внимание на хидеры - X-Cache: TCP_MISS или TCP_HIT + X-Check-Cacheable: NO

Тестируя из разных регионов, обнаружилось, что Amazon даже рядом не стоит с Akamai. 

Amazon Cloudfront CDN


Зачем нужен CDN ?

1. Разгрузить сервер раздающий контент
2. Ускорить загрузку сайта из разных регионов

CloudFront Amazon CDN доступен через Amazon WebServices. Очень легко начать. Возможно 2 типа конфигурации, когда пользователь закачивает свои файлы в S3, или же когда Amazon забирает файлы с вашего сервера и кеширует у себя.

Самый простой сетап - указываем в настройках CDN свой сервер, настраиваем кеширование в 24 часа, ну и прописываем URL Amazon у себя на странице для подгрузки статичного контента(js, css, картинок).

Когда пользователь открывает веб-страницу, запрос идет на Amazon-вский CDN, который либо подгружает статичный контент из своего кеша, либо обращается на сайт. Amazon CloudFront добавляет специальный header в http запрос, был hit по кешу или miss.


После подключения Amazon CDN, загрузка моих проектов из России упала почти на 30%, некоторые css файлы стали грузиться почти секунду, по сравнению с подгрузкой напрямую с серверов из штатов или с Hentzer.

Если погуглить на тему Amazon CDN is slow, можно увидеть много аналогичных вопросов на SO. Вот отличная статья на эту тему -

https://www.bizety.com/2015/11/07/amazon-cloudfront-vs-akamai-amazon-cloudfront-vs-cloudflare-the-ugly-truth/

Amazon CDN не лучшее решение, если хочется ускорить загрузку сайта. У них миллионы клиентов, ноды раздающие контент могут тормозить. Amazon Web Services предлагают огромное к-во сервисов, а не только CDN. Возможно качество и скорость CDN не сильно их волнует.


Для выбора CDN идеально подойдет компания которая специализируется исключительно на CDN, например Akamai, лидер индустрии. Или же такие решения как CloudFlare полностью проксирующие весь трафик на сайт, а также помогающие защититься от ddos атак. Однако CloudFlare не совсем CDN в чистом виде, т.к приходится менять DNS на их сервера. У меня есть опыт коллег использующих CloudFlare, загрузка их сайта из разных регионов ускорилась.

Можно посмотреть в сторону Rackspace, который такой же дешевый как Amazon, но использует сетку Akamai - http://blog.rackspace.com/rackspace-launches-cdn-partnership-with-industry-leader-akamai/

SampleRate vs BitRate

http://thestereobus.com/2008/01/12/sample-rate-and-bitrate-the-guts-of-digital-audio/


Sample rate - как часто захватывается аналоговый звук.
Bit rate - насколько хорошо описан звук. Т.е сколько данных(бит) мы захватывает за один тик. 

Например качество CD 44.1 khz, это значит, что sample rate - 44.1, происходит 44,100 захватов в секунду. BitRate у CD 16 bit, т.е  каждый семпл описан 2 ^ 16 = 65,536 битами. 



Codec negotiation



    
     [Offer]
      v=0
      o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com
      s=
      c=IN IP4 host.atlanta.example.com
      t=0 0
      m=audio 49170 RTP/AVP 0 8 97
      a=rtpmap:0 PCMU/8000
      a=rtpmap:8 PCMA/8000
      a=rtpmap:97 iLBC/8000

m =  media type format and transport address.

Т.е порт 49170, транспорт RTP/AVP. Дальше кодеки - 0,8 и 97.
В rrpmap находится меппинг констант на конкретный кодек. То есть 0 - это G.711 uLaw, 8 это  G.711 ALaw. 97 - это iLBC кодек.

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


   
     [Answer]
      v=0
      o=bob 2808844564 2808844564 IN IP4 host.biloxi.example.com
      s=
      c=IN IP4 host.biloxi.example.com
      t=0 0
      m=audio 49174 RTP/AVP 0
      a=rtpmap:0 PCMU/8000
      m=video 49170 RTP/AVP 32
      a=rtpmap:32 MPV/90000

SDP payload example
Codec negotiation RFC

Payload format for the Speex
Speex vs Nellymoser

Asterisk QoS

http://kb.smartvox.co.uk/voip-sip/rtp-jitter-audio-quality-voip/
http://www.voip-info.org/wiki/view/Asterisk+RTCP

Как можно было б собирать QoS(quality of service) метрики на Астериске ?

1. Руками
asterisk -r 
rtcp set debug on 

RTCP статистику можно будет увидеть в /var/log/asterisk/full. Что значит каждая из переменных можно посмотреть по последней ссылке.

sip show channelstats -покажет активные каналы, в том числе packe loss ratio. Можно написать шеловский скрипт, который бы выполнял в цикле asterisk -rx "sip show channelstats" > rtcp_stats.log После чего эту статистику можно было б распарсить.

2. Pinefrog

В Asterisk 12 вроде как появился Pinefrog, который должен уметь логировать данные прямо в базу. Возможно он не в транке, а в каком-нибудь бранче. В этой же статье описан Pinefool - packet loss concealment механизм. Если обнаружен packet loss, Asterisk отправит копию последнего полученного пакета. http://www.voip-forum.com/opensource/2013-04/asterisk-rtp-improvements/

 3. Сторонние тулзы.
Например - http://www.voipmonitor.org/.
Работает как снифер пакетов, очевидно, добавляет overhead.



MultiKey из двух int

private long key(int int1, int int2) {
  return ((long)int1 << 32) + int2;
}

Cтоит ли использовать Play!

Play! – хорошо раскрученный стек для быстрой  разработки java web приложений.  Включает в себя web layer,шаблоны, локализцию, jpa, разные утилиты для работы с почтой, шедулер для джоб, а также большое количество плагинов. Такой мини J2EE стек, позволяющий писать в PHP стиле =) Может запускаться как и standalone приложение, так и паковаться как war и запускаться в сервлет-контейнере. Основной особенностью является возможность видеть изменения в браузере без редеплоя. Для разработчиков, которые точно не уверены, что делают их код – это очень удобно. Можно нажать F5 и сразу посмотреть =)
Поделюсь некоторыми своими субъективными соображениями.

Минусы:
1) Отсутствие стадартной maven структуры проекта. Вместо этого dependencies.yml файл, где надо указывать artifact-Id, group-id, version. После этого командой play dependencies –sync нужные зависимости скачиваются в папку lib. Очень неудобно. Вызов этой команды удаляет .svn файлы из папки lib =) Play использует maven, чтобы ресолвить зависимости, но другие возможности maven недоступны.

2) Очень удобно создавать war файл из проекта, командой play war. Жаль, что она не работает, если в проекте есть .svn файлы. Соответственно, надо либо их удалять, либо делать svn import, который импортирует только закомиченный код.

3) Если же есть желание запускать play как standalone, готовитесь к проблемам на проде. По ссылке stackoverflow я описал проблему, с которой столкнулся.

4) Отсутствие нормальной интеграции с DI, а также какого-либо решения из коробки. Я использовал Google Guice. Как заинжектить бины в контроллер, методы которого обязаны быть статическими ?  Вот так-  requestStaticInjection(SipController.class); Не всегда удобно. Если же бин обращается к JPA из конструтора при использовании Guice, то он не сможет обращаться к JPA, придется открывать сессию руками. play.Play.plugin(JPAPlugin.class).startTx(true);

5) Контроллеры обязаны быть статическими, не всегда удобно писать юнит-тесты и вообще код.

6) Чтобы получить IP адрес запроса, надо написать - Http.Request.current().remoteAddress. Мне не очень нравится такой стиль. Все состояния хранятся в каких-то ThreadLocal статических переменных.

7) Многие фреймворки интегрируются посредством создания listener или servlet в web.xml. Но здесь нет web.xml. Я хотел использовать hessian, но его никак не подключить. Пришлось использовать REST.

8) Отсутствие таких мега-фич, как JMX мониторинг из коробки. Например в Spring есть ManagedResource аннотации, которые позволяют экспозить бин через JMX. Пришлось реализовать самому, в рантейме регистрируя DynamicMBean.

9) В контроллерах нельзя сделать forward, только redirect. Если из одного контроллера надо вызвать другой, надо редиректить ему запрос. Пример с контроллерами:
public static void index() {
  doAction();
}
public static void doAction() {}
Если метод doAction  объявлен как public внутри этого же контроллера, то произойдет редирект! если private, то просто произойдет вызов этого метода. Если надо вызвать doAction из другого контроллера, то произойдет редирект, возможности forward сделать нету. И на доках Play! написано, что это удобнее.

10) Вся сессия хранится на клиенте в кукисах. поэтому размер её ограничен, можно конечно самому организовать сессию.  Но насколько секьюрен такой поход?  Например, когда пользователь логиниться, кладем его email в клиентские кукисы, предварительно шифруя.  Когда клиент придет с этими же кукисами, кукисы будут дешифрованы.  

11) Если заглянуть внутрь play, то можно увидеть код, не внушающий доверя. Вместо метода return, пробрасывается  исключение. Который потом обрабаывается где-то уровнем выше. Т.е метод можно вернуть разные типы исключений =)
Класс ActionInvoker
                // OK, re-throw the original action result
                if (actionResult != null) {
                    throw actionResult;
                }


Плюсы:

1) Очень удобная система шаблоном.

2) Много плагинов, правда единственный, который я хотел использовать greenscript, работал с багом, иногда возвращая 200, вместо 304.

3) Не нужно деплоить изменения. На мой взгляд, довольно сомнительно, если уж так хочется нажимать F5, используйте JRebel.


Вывод:

- Удобен для начинающих разработчиков и очень прост в использовании.
- Ставит в определенные рамки, выйти за которые не всегда удается.
- Заставляет писать код в непривычном стиле.
- Код фрейморвка не внушает доверя.



RMI в Одноклассниках

Для обмена данными между серверами Одноклассники "изобрели" собственный RMI сервер, на основе паттерна proactor, который можно найти на гитхабе rpc-samples

Изначально они использовали вроде бы Netty, но потом написали свое решение с нативными вставками Си, с использованием JNI. Основная мотивация - перфоманс.

Под нагрузкой Netty создавал огромное количество объектов, которые не собиралась во время GC. Вроде бы это как-то было связано с использованием finalize у класса сокет. Они пытались хакать jdk, заменяя класс сокет собственной имлементацией с переписанным методом finalize, но получалось только хуже. В итоге написали свой сервер.

А также они используют самописный механизм сериализация. Джавовская сериализация довольно медленная, есть альтернативные решения вроде Jboss Serialization, который быстрее. Но клиент и сервер при использовании Jboss Serialization должны использовать идентичные версии классов. Другое решение - для каждого класса писать сериализацию самостоятельно. Однако это не удобно, если у тебя тысячи классов.


System.out To Log4J

Порой необходимо сделать так, чтоб log4j выводит аутпут на консоль, при использовании e.printStackTrace() и System.out.println(""); Для этого при загрузке приложения достаточно выполнить следующий код.



   private static final Logger logger = Logger.getLogger("sdout");

    public static void tieSystemOutAndErrToLog() {
        System.setOut(createLoggingProxy(System.out));
        System.setErr(createLoggingProxy(System.err));
    }

    public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
        return new PrintStream(realPrintStream) {
            public void print(final String string) {
                realPrintStream.print(string);
                logger.info(string);
            }
        };
    }

Кластеризация mongoDb

MongoDb поддерживает репликацию баз данных в том числе в режиме реального времени.

Цели репликации в mongoDb

  • Failover.  Пережить падение железа
  • Улучшение перфоманса. Можно добиться улучшения производительности для приложений, где количество чтений значительно превосходит количество записей. Распределив нагрузку на чтение по разным серверам.
  • Уменьшение отклика. Позволить разным нодам общаться с теми репликами, которые находятся наиболее близко географически.
  • Есть дубликат базы, который обновляется раз в 30 минут.  Например, мы можем захотеть увидеть какие-то тенденции, каким образом обновляются данные, сравнивая их между собой (сравнивая данные в реплике и основной базе)
  • Например, нам надо делать бекапы с данными, которые меняются очень часто и данных много. Если использовать обычные инструменты для бекапа, то это может занимать много времени.
  • Строить какие-то сложные отчеты по данным. Запросы могут оказаться довольно тяжелыми для основной базы, поэтому лучше делать их на реплике.
  • Имеется стаджинг, который требует реальных данных для тестирования. Тестирование кода с использованием базы продакшена может привести к потере данных. Имея репликациюв виде стеджинга этого не произойдет

Oplog

Что-то вроде транзакционного лога (журнала), который использует mongoDb. Oplog имеет фиксированный размер (настраиваемый), новые записи со времнем перетирают старые. Slave переодически просматривает Oplog в поисках изменных данных, и синхронизируется с мастером. Размер лога должен быть выбран таким образом, чтобы Slave “успевал” понять, насколько далеко он находится от мастера до того, как новые изменения в Oplog перетрут старые.


Типы репликаций

  • Single master/ Single slave. Простейший вид репликации, не предусматривает автоматического failover. Если мастер упадет, приложение должно само определить, что пора идти к Slave
  • Single master/ Multiple slave. Трудно представить зачем это может быть нужно
  • Multiple master/ Single slave Например, есть 2 разных базы, 2 разных приложения, расположенных на разных серверах. Все данные можно реплицировать в один Slave, например для построения тяжелых отчетов. Важно то, что нельзя реплицировать одну и ту же базу с разных мастеров. (имена баз должны быть уникальны)
  • Cascade replication. Master - > Slave/Master - > Slave. Данные пишутся на основной мастер, сразу же на Slave/Master, а потом через какое-то время на Slave. 
  • Master/Master replication. Кластер всегда будет оставаться в синхронизированном состоянии, клиенты могут писать и читать с обоих инстантов.
  • Intervealed replicationМожет быть использовано для экономии места, когда есть несколько приложений, работающих на разных серверах. Один может быть мастером для одной базы и слейвом для другой и наоборот. Master app A / Slave app B ⇔ Master app B / Slave app A
  • Repilca pairsDeprecated since mongoDb 1.4 in favoe to Replica Set (другой механизм) Отличается от Single master/Single slave тем, что в случае падения мастера, слейв возьмет на себя его роль. При чем когда мастер неожиданно проснется после своего падения, он поймет, что пора ему становится slave-ом. Понятно, что в таком случае приложение должно знать об обоих серверах. Драйвера для всех языков mongoDb поддерживают эту возможность.
  • Replica set. Replica set поддерживают намного более гибкую конфигурацию чем replica pairs.  Если в кратце, серверов может быть много в реплике каждый из них - это secondary/primary и active/passive. (я пользуюсь терминологией mongoDb)  Master - один, это и есть primary. Secondary - это slave-ы, их может быть много. В случае падения master, все слейвы, у которых статус active будут участвовать в “голосовании”, кто же из них станет master. Passive слейвы мастером никогда не станут, т.к возможно используются для отчетности.

Шардинг в mongoDb

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

Используется как в реляционных база данных, так и для mongoDb. Фактически это разбиение одной “таблицы” на несколько разных “таблиц”. Это может работать как на одном сервере, так и на разных инстантах. На одном сервере это делается для того, чтоб быстрее работала выборка, меньше времени тратилось на перестройку индекса и т.п. Т.е была одна таблица с 5 миллиона строк, стало 2 по 2.5 миллиона. На разных серверах, чтобы увеличит bandwith, I/O, etc.

Для того, чтобы приложение понимало, куда надо идти, используется некая hash функция, например, если userId % 2 == 0, то один сервер, в противном случае другой сервер. Часто это логика находится в самом приложение, чтобы приложение понимало, куда ему идти.  Для реляционных баз данных, тут есть ряд проблем - добавление нового сервера (шарда), необходимо как-то менять хеш функцию, а иногда перебалансировать данные с одного сервера, на новый. Также очевидно, что не удаться писать какие-то сложные джойны или другие SQL запросы, вся выборка должна идти по FK. Очевидно, что в случае с реляционными базами данных, далеко не каждую таблицу можно разбить на партиции.  Точнее разбить можно, но поиск по разным партициям придется писать самому. Например, есть таблица с объявлениями, селект с поиском по некому слову в одной таблице вернет результат сразу. В случае партицированния, придется отправить несколько запросов на разные сервера, а потом сложить результат. Хорошо для шардинга в реляционных базах данных подходят “изолированные” данные. Например, каждый пользователь, сохраняет что-то там у себя, и никому не интересно, что именно.


Предположим, что есть таблица, в которую пишутся пользовательские логи, в конце каждого месяца необходимо составлять отчет по этим логам. Таблица растет очень быстро и имеет миллионы, а то и миллиарды данных. Работа с такой таблицей сильно грузит базу, учитывая то, что нам нужны данные только за последний месяц, можно партицировать (разбить таблицу) на 2 части. Текущая (текущий месяц), всё остальное. Запись будет идти только в текущую таблицу, отчеты строятся тоже только по ней. А остальные данные хранятся для истории в другой таблицы. Многие базы данных предоставляют встроенные механизмы для партицированная. Писать код, который переносит данные не придется.

Шардинг в mongoDb

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


MongoDb, настроенный для шардинга,  может состоять из несколько реплик mongod процесса (сама база), несколько независимых между собой mongos процессов, и реплики config серверов. Код приложения обращается к одному из mongos процессу  (их может быть сколько угодно, т.к у них нет ничего общего). Mongos процесс обращается к config серверу, чтоб определить, на какую шарду или к каким шардам ему идти за данными. На config сервере хранится диапазон ключей -> значений. Где диапазон ключей - это, например A-M, т.е первые буквы имен пользователей, а значение название шарды.

A-M -> shard1
N-U -> shard2
F-Z  -> shard3
Mongos понимает к какой ноде ему идти, и обращается напрямую, возвращая данные клиенту. Обращения могут затрагивать как одну ноду (обращение по ключу для шардинга), так и несколько (обращение не по ключу или получение списка. Если заданы параметры сортировку, то mongos получает данные от нескольких нод, и сортирует данные у себя перед тем как отдать клиенту.

Все сущности mongos, mongod, config сервер могут быть запущены на разных серверах.


Выбор ключа для шардинга.

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


Вся данные делятся на чанки (chunk), когда чанк достигает размера 64 мб, он делится на 2 по 32.  Чанк - это набор смежных данных. Когда размер шарда превысит допустимый, чанки будут перемещены на другую шарду.  

profiler tools

Visual VM -  как standalone, так и плагин к eclipse
Eclipse memory analyzer

Профилрование своими руками - доклад Елизарова

CSRF Security Error DWR Tomcat7

в server.xml   Server-> Service -> Engine -> Host в элемент добавить useHttpOnly
<Context useHttpOnly="false" />
подробнее тут

Поиск по приложениям ВКонтакте

Сегодня обнаружил, что поиск ВКонтакте по приложениям больше не учитывает описание, а только название. Надо как можно больше слов впихивать в название =)

Балансировка нагрузки Amazon с автомасштабированием

Здесь можно почитать статью на тему авто масштабирования в Amazon
Есть и другой сервис scalarium, который позволяет процесс автоматизировать слегка

Code syntax highlighter with blogger dynamic view


Вышла новую версия google blogger с обновленным интерфейсом.  Возникли сложности при подсветке кода в динамических шаблонах

Чтобы подсветка работала в статических шаблонах, надо редактировать html код шаблона, включить туда css и js. (при файлы css, js должны быть на отдельном хостинге).  А также вызвать некую js функцию, как описано в документации к хайлатеру.

Подсветка кода перестала работать в динамических шаблонах, т.к их невозможно редактировать. В каждом посте придется включать js код, в посте, который использует подсветку.

Подробнее тут и тут

Kickstrap

fork twitter bootstrap c темами - kickstrap

Разница между Mediator и Observer

Observable просто имеет список observer, когда происходит какое-то сообытие, он может сделать broadcast, все обсерверы получат уведомление. Observable работает с одним типом интерфейса, и может вызвать только один метод. В Java есть готовая имлементация обоих классов.


Mediator - это некая сущность, которая знает всё о других. Другие знают о медиаторе, но не знают ничего друг от друге. Медиатор управляет другими, за счет получения от других некоторых событий. Чаще всего используется в UI. Например есть кнопка, происходит нажатие на кнопку, отправляем медиатору сообщение - "нажата кнопка". Медиатор берет и делает, например, грид не активным, прячет другую кнопку, и меняет цвет фона. Кнопка, отправившая событие ничего не знает о том, что произошло. Тоже достигается слабая связанность между компонентами.

Subversion cache

Поставил Jenkins, начал настривать. Создал новую job, ввел URL от repohosting, нажал build. И о чудо, Jenkins умудрился вычекать мой репозитарий. При этом у моего репозитария не настроен доступ для анонимов, а никакие пароля я никуда не вводил. Это мне оч понравилось

Оказывается он умудрился взять доступ из SVN кеше, который лежит у меня вот тут -
D:\Documents and Settings\Администратор\Application Data\Subversion

Этот кеш создала tortoise svn. Вот такие пироги

Blocking ThreadPool

Если создать экзекутор Executors.newFixedThreadPool(1) таким образом, то для задач, которые не могу быть обработаны будет использоваться безразмерная очередь, в итоге эта конструкция может уйти в OOM, например. Можно использовать блокирующую очередь, но тогда придется определить RejectionPolicy, т.е, что экзекутор должен сделать в том случае, если размер очереди ожидающих задач переполнен.

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

BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(10);
RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy();
ExecutorService excutorService =  new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, blockingQueue, rejectedExecutionHandler);


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


Другой способ, это использовать семафор, поток, который сабмитит таску, заблокируется

final Semaphore semaphore = new Semaphore(bound);
    try {
     semaphore.acquire();
        executor.execute(new Runnable() {
            public void run() {
                try {
                    command.run();
                } finally {
                    semaphore.release();
                }
            }
        });
    } catch (Exception e) {
     semaphore.release();
    }

java.util.concurrent очереди

Очереди

ConcurrentLinkedQueue - не блкирирающая очередь, не имеющая лимита. Наследуется от java.util.AbstractQueue

Также есть интерфейс public interface BlockingQueue extends Queue. И 5 имлепентаций блокирующих очередей.

Можно положить в очередь объект 4 разным способами

  •  кидает исключения, если очередь пуста (заполнена)
  •  возвращает true/false в зависимости от того, удалось ли совершить операцию.
  •  блокирует поток
  •  блокирует поток на определнное время (offer(e, time, unit))


  • ArrayBlockingQueue. Очередь с фиксированным размером. FIFO
  • DelayQueue Безразмерная очередь, элемент может быть взят из очереди, когда Delay кончился
  • LinkedBlockingDeque размерность очереди опциональна
  • LinkedBlockingQueue. FIFO
  • PriorityBlockingQueue приоритетная очередь
  • SynchronousQueue. Блокируащая очередь. Основное отличие от LinkedBlockingQueue в том, что метод put на пустой очереди будет блокироваться, если нет тредов, который висят в ожидании на take. Если 1 тред вызовет put, а второй take, то оба треда разблокируются одновременно. Или например можно использовать offer на очереди, дальше, если есть треды, готовые обработать этот запрос, запрос обработается, в противном случае, тред вызывающий offer может кинуть исключение или обработать задачу самостоятельно.

Synchronizers

CountDownLatch

Приостанавливают выполнение до тех пор, пока не выполнится терминальная точка какая-та. Работает как ворота, пока ворота закрыты, не один поток не может войти, когда ворота открываются, все потоки могут войти.

Обычно используются, для того, чтоб предотвратить выполнение некоторых операций, пока какая-та активность не выполнена.

Примеры
  • Быть уверенным в том, что выполнение не началось до того, как ресурс не активизировался. Т.к выполнение требует активизированного ресура.
  •  Быть уверенным, что сервис не стартанул, пока другие сервисы, которые от него зависят не стартанули.
  •  Ждем, когда все игроки в многопользовательской игре стали готовы, чтоб начать игру.


CountDownLatch - пример такого синхронизатора, когда латч имеет некий счетчик, который иницизилиться при создании. Далее это счетчик уменьшается, и до тех пор, пока не станет 0, все потоки будут заблокированы.

CyclicBarrier

аналогично Latches, но не одноразовый

Semaphore

Указывают количество объектов, которые могут обращаться к ресурсу. Используются например в конектион пулах и т.п

Два основных метода -
  • acquire() - пытается "получить доступ", блокируется в противном случае.
  • acquire(int permits) - может пататься взять сразу несколько permit

release - уменьшает счетчик пермитов, отпускает как бы его.

Может быть как fair, так и non-fair. Если fair, потоки, которые пытаются получить ресурс встают в FIFO

Можно использовать так называемым бинарный семафор, это когда семафор создается с 1 пермитов. И он ведет себя также как Lock, за исключением того, что вызвать release может другой поток, не тот, который вызвал acquire и что-то там начал делать

Сортировка

алгоритмы сортировки, визуализованные

Сортировка пузырьком

Сортировка методом выбора.

Сортировка методом вставки.
Подходит для уже упорядоченных элементов. И доходит до O(N), если элементы достаточно упорядочены.

Сортировка Шелла

Алгоритм использует сортировку методом вставки. O(N 3/2)

Сортировка слиянием.

N*log(N). Требует доп. памяти. В jdk6 используется по умолчанию для метода Collections.sort. Только модифицрованный её вариант.

Сортировка пирамидальная.Тоже требует доп. памяти, т.к использует спец. структуру пиирамида.

Быстрая сортировка.
Если данные недостаточно случайны, может ухудшиться до O(N2).

TimSort.
Относительно молодая сортировка. Лучшая по эффективности на данный момент. Используется в python по умолчанию, а также в android jdk. Возможно будет использовать в jdk7 по умолчанию. За основу взята сортировка слиянием и сортировка методом вставки.

MapReduce в MongoDb

MapReduce - это обычная группировка, не больше не меньше. Сначала надо выбрать ключ, по которому производится группировка. Ну а потом придумать, как обрабатывать получившиеся значения и что возвращать методом Reduce. В mongoDB все это дело пишется на серверном Javascript.

Функция map должна вызывать функцию emit, которая принимает пару ключ значение. Ключ - это поле, по которому осуществяется группировка. Значения - это значение, которое попадет в функцию reduce.

След. функция reduce, принимает key и vals. Vals - это всегда коллекция, т.к туда пишутся результаты прошлых вызовов выборок. Пример функции reduce

function(key, values) {
    var result = {count: 0, likes: 0};

    values.forEach(function(value) {
      result.count += value.count;
      result.likes += value.likes;
    });

    return result;
  }


Есть еще функция function finalize(key, value) -> final_value она будет вызвана после того, как по ключу не будет больше вызываться функции reduce. Это можно использовать, чтоб завершить какие-то финальные дейсвтия. Т.к мы не знаем в функции reduce вызываемся мы последний раз или нет.


Также нужно указать параметр out. Фактически - это куда будет литься результирующая коллекция.

{ replace : "collectionName" } - значение по умолчанию, замена существующей коллекции.


Вот в этом куске кода, над коллекцией payments мы делаем mapReduce, в качестве ключа мы используем payment_time, который сокращен до точности часа. Этот код позволит нам получить количество платежей по часам за весь период, в течении которого совершались платежи.

db.system.js.save({
    "_id" : "aggregatePayments",
    value: function () {
     db.payments.mapReduce(
             // функция map
             function() {
                 var k = clone(this.payment_time);
                 k.setMinutes(0);
                 k.setSeconds(0);
                 k.setMilliseconds(0);
                 emit(k, this.amount);
             }, 
             // функция reduce
             function (key, vals) {
                 var total = 0;
                 for (var i = 0; i < vals.length; i++) {
                     total += vals[i];
                 }
                 return total;
             },
             {
              out : {merge : "chargebackByDay" }
             }
     );
    }
};


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

Eclipse hotkeys

Eclipse hot keys

CTRL+Q - последнее место изменения
Ctrl+E - переключаться между открытыми окнами

Eclipse static imports

Вместо того, чтобы в каждом новом классе писать Assert, потом нажимать CTRL-1, подключать нужный импорт, и писать assertEquals, можно подключить пакеты, статичные методы которых будет вываливаться в дропдауне для код-ассиста. Java->Editor->Content Assist-> Favorites

Подробнее тут

Lock. ReentrantLock. Synchronized. Fair lock vs nonfair lock

ReentrantLock может быть создан как с fair lock, так и с unfair lock. То же самое с Semaphore. Fair lock - это когда потоки получают доступ к ресурсу в том порядке, в котором они захотели захватить блокировку на ресурс. Unfair - это когда поток, который оказался в нужном месте в нужный момент, заберет блокировку себе, даже если он пришел позже чем остальные потоки. Пропуская способность unfair lock может быть значительно больше чем fair lock при опредленных обстоятельствах. По умолчанию ReentrantLock, а также блок synchronized используют nonfair лок.

В Java 5 ReentrantLock быстрее synchronized. В 6 по скорости одно и то же. Просто ReentrantLock предоставляет чуть больше возможностей, tryLock, lockInterruptibly, lock по таймауту и т.п

ReadWriteLock

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

private final ReentrantReadWriteLock readWriteLock =  new ReentrantReadWriteLock();
private final Lock read  = readWriteLock.readLock();
private final Lock write = readWriteLock.writeLock();


private Map<String, String> map = new HashMap<String, String>();
   
public void set(String key, String value) {
   write.lock();
   try {
      map.put(key, value);
    } finally {
       write.unlock();
     }
 }
    
public String get(String key) {
  read.lock();
  try{
     return dictionary.get(key);
   } finally {
       read.unlock();
    }
}


Java GC

JVM хранит память в двух местах

1) PermGem - метаданные об объектах и классах. А также пул строк вроде как ?

Размер PG можно задать двумя параметрами JVM: -XX:PermSize – задаёт минимальный, или изначальный, размер PG, и -XX:MaxPermSize – задаёт максимальный размер


2) Heap – основной сегмент памяти, где хранятся все ваши объекты. Heap делится на два подсегмента, Old Generation и New Generation

2.1) New generation делится в свою очередь еще на 3 сегмента
2.1.1) Eden
Новые объекты создаются в Eden
2.1.2) Survivor1
2.1.3) Survivor2
2.2) Old generation

Существует несколько алгоритмов, по которым может работать GC
1) Copy
Копирует все помеченные объекты из Eden в Survivor1 и т.п. При этом все потоки останавливаются, пока GC не закончит свою работу. Понятно, что он нигде не используется или возможно в каких-то исключительных ситуациях

2) Mark-Sweep-Compact Collection.
Я так понимаю, современный алгоритм, который используется во всех JVM
У алгоритма три этапа:
«Mark»: помечаются неиспользуемые объекты
«Sweep»: эти объекты удаляются из памяти.
«Compact»: объекты размещаются, занимая свободные слоты, что освобождает пространство на тот случай, если потребуется создать «большой» объект. Т.е как бы убираются дырки

Утилиты

jvisualvm утилита из коробки JDK, чтобы смотреть, как работает сборщик мусора

Настрофки
-Xms определяем исходный/минимальный размер heap в 512 мб
-Xmx определяем максимальный размер heap в 512 мб
-XX:NewRatio соотношение old generation к new generation
-XX:+PrintGCTimeStamps, -XX:+PrintGCDetails и -Xloggc:gc.log JVM печатает дополнительную информацию касаемо garbage collection в файл gc.log
-XX:PermSize – минимальный размер PG
-XX:MaxPermSize – максимальный размер PG

Java Deadlock

Наиболее частая причина дед-локов - это порядок при котором потоки берут лок на объекты. Один поток берет лок на объект A и ждет, второго потока, который взял лок на объект B, который в свою очередь ждет, когда 1 поток отпустит объект A.

Вот пример такого лока, код, который, казалось бы, работает верно, но может привести к дедлоку, если from и to поменяются местами при следющем вызове.

	public void transerMoney(Account from, Account to, Dollar amount) {
		synchronized (from) {
			synchronized (to) {
				if (from.getBalance().compareTo(amount) < 0) {
					throw new InsufficientFundsException();
				}
				from.debit(amount);
				to.credit(amout);
			}
		}
	}
как можно переписать этот код ? ну например можно определять хеш объекта, чтоб установить порядок лока.
	public void transerMoney(Account from, Account to, Dollar amount) {
		int fromHash = System.identityHashCode(from);
		int toHash = System.identityHashCode(to);
		if (fromHash < toHash) {
			synchronized (from) {
				synchronized (to) {
					transfer();
				}
			}
		} else if (fromHash > toHash){
			synchronized (to) {
				synchronized (from) {
					transfer();
				}
			}						
		}
	}

Можно также использовать интерфейс Lock и явно создать ReentrantLock
	public void transerMoney(Account from, Account to, Dollar amount) {
		if (from.lock.tryLock()) {
			try {
				if (to.lock.tryLock()) {
					try {
						transfer();
					} finally {
						to.lock.unlock();
					}
				}
			} finally {
				from.lock.unlock();
			}
		}
	}

tryLock возьмет лок или сразу же вернет false, если он не может взять lock. В коде выше например можно добавить проверку, которая определяет удалось ли нам осуществить операцию, при необходимости повторить её снова.

Хранение информации во внешних источниках

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

B-tree

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

Существуют еще разновидности в виде B+деревьев и R-деревьев.

Индексирование

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

Хеширование

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



Доп. информация

1) citforum.ru/programming/theory/sorting/sorting2.shtml#5
2) «Системы баз данных: полный курс» авторства Ульмана, Уидома и Гарсиа-Молина
3) «Database Systems: The Complete book»

Многопутовые деревья

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

Деревья 2-3-4

Сбалансированные деревья, которые ведут себя также как красно-черные деревья, обладают чуть меньшей эффективностью, но более простые в реализации. У 2-3-4 деревьев каждый узел может иметь до 4 потомков 3 элементов данных.

- Узел с одним элементов данных всегда имеет двух потомков.
- Узел с двумя трех потомков
- Узел с тремя четырех потомков.

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

Эффективность 2-3-4 деревьев

В деревьях 2-3-4 узел может иметь до 4 потомков. Если бы все узлы дерева были б заполнены, то поиск бы занимал log от N по основанию 4, или log2(N+1/2). Т.е высота дерева 2-3-4 может быть в два раза меньше чем высота обычного двоичного дерева. С другой стороны каждый узел содержит больше элементов, т.к для проверки элементов используются линейный поиск. Получается сложность поиска - M*log4N, где M - это количество элементов в узле. Но на самом деле все это ерунда и сложность алгоритма поиска примерно такая же как и у красно-черных деревьев O(logN)

2-3 деревья

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

B дерево

B-дерево удобен при нахождении данных во внешней памяти, например на жестком диске.

B-деревья по умолчанию используются как индексы для . postgresSQL Хотя он поддерживает и другие индексы, например хеширование

Основная идея в том, что чтение с диска осуществляется блоками. Например, если у нас есть таблица с миллионом записью, где каждая запись весит N кб, то чтение производится сразу многих записью, размером N*16, например. Разумеется количество одновременно считываемых записей зависит от размера записи, от размера считываемого блока и т.д.

B-деревья, это те же 2-3-4 деревья, только вместо максимального количество в 4 потомка, а сколько угодно потомков, например 16. Т.е каждое обращение к диске считывает 16 записей из базы в память. Каждый блок данных содержит ссылку на узлы, находящиеся в других блоках памяти

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

Двоичные деревья

Какие бывают двоичные деревья

- двочиные дервья поиска.
- для вычесления префиксных, суфискных операций.
- другие алгоритмы (например дерево Хаффмана для шифрования).
- пирамида

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

Поиск занимает logN, правда, как следсвтие другие операции - вставка, удаление тоже logN. Понятно, что в обычном списке операция поиска занимает N. В

Обход двоичного дерева

Симметричный обход
Прямой обход
Обратный обход

Обход - простейший рекурсивный алгоритм, типа
1) Вызов самого себя для обхода левого поддерева узла
2) Посещение узла
3) Вызов самого себя для обхода правого поддерева узла

Разница в трех обходах упомянутых выше - всего лишь порядок операций.

Пирамида

Пирамида - это двоичное дерево. Обаладет след. характеристиками.

1) Все уровни дерева содержат все возможные узлы ( хотя последний может быть заполнен лишь частично)
2) Обычно реализуется на базе массива.
3) Ключ каждого узла больше (либо равен) ключей его потомков.

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

Сбалансированные двоичные деревья

Для того, чтоб операция поиска всегда занимала время logN, дерево должно быть сбалансировано.

Красно-черные деревья.

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

AVL деревья
Из всех разновидностей сбалансированных деревьев, первым появилось AVL дерево. В AVL деревьях в каждом узле хранится дополнительная информация: разность весов левого и правого поддеревьев. Это разность не может быть больше 1. После вставки нового узла выполняется одиночный или двойной поворот для выравниания высот. Затем алгоритм двигается вверх и проверяет узел, выравнивает высоты в случае необходимости. И так до корня. Поиск в AVL дереве выполняется за logN, однако вставка и удаление требует двух проходов от корня до узла, и от узла до корня. Поэтому эти деревья уступают красно-черным деревьям и используются редко.

Avoid finalizers

У всех объектов есть finalize метод, который вызывается, когда сборщик мусора удаляет объект. Это может быть использования для освобождени ресурсов, например I/O или сокетов. Finalizer не дает никакой гарнатии, когда и как они будут вызваны. Во многих случаях комбинация finally и вызов метода close у ресурса предпочтительнее. Единственное исключение, финалайзеры могут пригодиться, когда надо управлять объектами, которые держат ресурсы, полученные нативными методами

JVM shutdown. Shutdown hooks

Можно зарегистрировать некую таски, которые будут вызваться при остановке JVM.

		Runtime.getRuntime().addShutdownHook(new Thread(){
			LogService.performCleanup();
			FileService.performCleanup();
		});

Executor framework

Создание потока дорогая операция, для более удобного управления потоками используется Executor framework, а также для кеширования потоков.

Executors.newFixedThreadPool();

Добавляет в пул таски, по мере добавления клиентов до максимального размера пула. Переиспользует ранее созданные потоки. Если поток выдал Runtime исключение, он будет заменен другим потоком. Если делается сабмит новый таски, а пул полностью занят, то таска будет ждать.

Executors.newCachedThreadPool();

Добавляет в пул таски, используя ранее созданные потоки. Если отработанный поток висит какое-то время в состоянии idle, то по истечению 60 сек (это настраивается) он умирает. Этот пул хорош для создания большого количества коротких тасков

Executorts.newSingleThreadExecutor();

Executorts.newScheduledThreadExecutor();

Часто, когда мы сабмитим таску в executor, мы не работает с абстракцией Runnable, поэтому мы не знаем, что из себя представляет эта таска, и любой RuntimeException может привести к тому, что мы "потеряем поток". Поэтому лучше сабмитить таски, внутри try catch finally блока. Например Swing использует эту технику, для запуска "неизвестного" кода, который пишут пользователя. Если бы все свинговое приложение загибалось из-за NullPointerException из-за кривого кода пользователя, это было б не очень хорошо.

	public void run() {
		Throwable thrown = null;
		try {
			while (!isInterrupted()) {
				runTask(getTaskFromWorkQueue());
			}
		} catch (Throwable e) {
			thrown = e;
		} finally {
			threadExited(this, thrown);
		}
	}


Еще есть такой интерфейс как UncaughtExceptionHandler, который можно указать при создании ThreadPoolExecutor, если он не указан, что вылетании Runtime исключения, ошибка просто выводится на консоль, интерфейс позволяет переписать это поведение

Task cancellation. Poison Pills

Poison Pills могут быть использованы для остановки consumer/producer связки. Идея, в том, что producer в момент, когда ему сказано остановиться добавляет в блокирующую очередь Poison Pill. Consumer, при извлечении объекта из очереди сравнивает его с Poison Pill и если consumer видит такой объект, то он останавливает свою работу.

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


public class PoisonPillsService {
	
	private static final String POISON = \"POISION_PILL\";
	
	private final BlockingQueue<String> queue; 
	
	private ConsumerThread consumer;
	private ProducerThread producer;
	
	public PoisonPillsService() {
		queue = new LinkedBlockingQueue<String>();
	}
	
	class ProducerThread extends Thread {
		public void run() {
			try {
				produce();
			} catch (InterruptedException e) {
				while (true) {
					try {
						queue.put(POISON);
					} catch (InterruptedException retry) {}
				}
			}
		}
		
		private void produce() throws InterruptedException {
		}
	}
	
	class ConsumerThread extends Thread {
		public void run() {
			try {
				while (true) {
					String s = queue.take();
					if (s == POISON) {
						break;
					}
					consume(s);
				}
			} catch (Exception e) {}
			
		}
		private void consume(String s) {
		}
	}

	public void start() {
		consumer.start();
		producer.start();
	}
	
}

Теория вероятности

Независимые события, логическое умножение

P(AB) = P(A)*P(B)

Бросам два кубика шестигранных, какова вероятность того, что на одном выпадет 2, а на втором 5.
P = 1/6 * 1/6

Логическое сложение. Противоположные события
P(A+B) = P(A) + P(B) - P(AB)

Бросаем 2 монеты, какова вероятность выпадение хотя бы одного орла ?

Вероятность суммы двух совместных событий равна сумме вероятностей этих двух событий без вероятности их совместного появления

P = 1/2 + 1/2 - 1/2*1/2 = 3/4

Вероятность хотя бы одного события из группы событий

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

Вероятности попадания в цель при стрельбе из трех орудий таковы: p1 = 0,8; p2 = 0,7; p3 = 0,9. Найти вероятность хотя бы одного попадания (событие А) при одном залпе из всех орудий.

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

Вероятности событий, противоположных событиям, и (т. е. вероятности промахов), соответственно равны: q1 = 1 - 0.8. q2 = 1- 0.7. q3 = 1 - 0.9

P = 1 - q1*q2*q3 = 1 - 0.2*0.3*0.1 = 0.994


В викторине 100 000 вопросов. Вопросы задаются случайным образом. Какова вероятность того, что из 60 вопросов 2 повторяться ?


P = 1- (1 - 1/ 100 000) * ( 1- 2 / 100 000) * (1 - 3/ 100 100) .... * (1-59/ 100 000)

Task/Thread cancelation

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

public class WhileTrueCancelation implements Runnable {

 private volatile boolean cancelled;
 
 @Override
 public void run() {
  while (!cancelled) {
   // do job
  }
 }
 
 public void cancel() {
  cancelled = true;
 }
}



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

public class BrokenProducer implements Runnable {

 private volatile boolean cancelled;
 private final BlockingQueue<Integer> queue;
 
 public BrokenProducer(BlockingQueue<Integer> queue) {
  this.queue = queue;
 }
 
 @Override
 public void run() {
  while (!cancelled) {
 
   try {
    queue.put(produce());
   } catch (InterruptedException e) { }   
  }
 }
 
 public void cancel() {
  cancelled = true;
 }
 
 private int produce() {
  .... slow operation
 }
}




В таких случаях лучше использовать interrupt, ниже пример кода, где вызов метода cancel в случае блокировки на методе put кинет исключение.

При этом поток может быть закблокирован Selector-ом или I/O операции, а также wait, join и т.п. В этом случае вылетит java.lang.InterruptedException. Которое надо как-то обработать, например можно опять вызвать Thread.currentThread().interrupt(), если мы хотим просетать флаг, который проверяем.

При чем обычный лок, созданный блоком synchronized или скажем методом tryLock у Lock не будет никак реагировать на метод interrupt. Если нужно создать лок, который будет реагировать на метод interrupt у потока, внутри которого создается лок, то можно воспользоваться методом lockInterruptibly класса Lock, который кинет InterruptedException, если поток будет прерван

public class GoodProducer extends Thread {
 
 private final BlockingQueue<Integer> queue;
 
 public GoodProducer(BlockingQueue<Integer> queue) {
  this.queue = queue;
 }
 
 @Override
 public void run() {
  while (!Thread.currentThread().isInterrupted()) {
   try {
    queue.put(produce());
   } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
   }   
  }
 }
 
 public void cancel() {
  System.out.println(\"cancel\");
  interrupt();
 }
 
 private int produce() {
                
  return ... slow operation
 }
}


Метод interrupt потока либо выставляет текущий флаг isInterrupted false, если нет блокировки, либо кидает исключение


Аналогично метод interrupted, который возвращает true/false для потока и очищает (флаг isInterrupted в false) статус потока. Этот метод статичен и относится к текущему потоку. В отличии от isInterrupted, который не статичек и является методом класса Thread, этот метод не очищает статус потока

First message