Полагаю, те люди, которые говорят, что доказать, что многопоточная программа является поточно-ориентированной, невозможна, в некотором смысле верны. Произвольная многопоточная программа, закодированная без соблюдения строгих правил, просто будет иметь ошибки потоков, и вы не сможете достоверно доказать что-то, что не соответствует действительности.
Хитрость заключается не в том, чтобы написать произвольную программу, а в том, чтобы иметь логику многопоточности, достаточно простую, чтобы, возможно, быть правильной. Это может быть однозначно подтверждено инструментом.
Лучший такой инструмент, который я знаю, это CheckThread . Он работает на основе аннотаций или конфигурационных файлов xml. Если вы помечаете метод как «@ThreadSafe», а это не так, вы получаете ошибку во время компиляции. Это проверяется путем просмотра байтового кода для небезопасных операций, например, чтение / запись последовательностей в несинхронизированных полях данных.
Он также обрабатывает те API, которые требуют вызова методов в определенных потоках, например, Качели.
На самом деле он не обрабатывает взаимоблокировки, но их можно статически устранить, даже не требуя аннотации, с помощью такого инструмента, как Jlint . Вам просто нужно следовать некоторым минимальным стандартам, таким как обеспечение того, чтобы блокировки приобретались в соответствии с DAG, а не волей-неволей.