При этом ускорение программы с помощью многопоточных вычислений на нескольких процессорах ограничено размером последовательной части программы. Это так называемый закон Амдала.
Этот закон гласит следующее – В случае, когда задача разделяется на несколько частей, суммарное время её выполнения на параллельной системе не может быть меньше времени выполнения самого длинного фрагмента.
Согласно этому закону, ускорение выполнения программы за счёт распараллеливания её инструкций на множестве вычислителей, ограничено временем, необходимым для выполнения её последовательных инструкций.
Потоки имеют собственный стек вызовов, но также могут обращаться к общим данным. Поэтому у вас есть две основные проблемы, проблемы с видимостью и доступом.
Проблема видимости возникает, если поток A читает общие данные, которые позже изменяются потоком B, а поток A не знает об этом изменении.
Проблема доступа может возникнуть, если несколько потоков получают доступ и изменяют одновременно одни и те же общие данные.
Проблема видимости и доступа может привести к сбою в работе – программа перестанет реагировать и войдет в ступор или взаимную блокировку из-за одновременного доступа к данным, или может быть сбой безопасности – программа создаст неверные данные.
Как решаются эти проблемы мы обсудим позже.
Таким образом, каждое приложение имеет хотя бы один поток – или несколько, если учитывать «системные» потоки, которые выполняют такие функции, как управление памятью и обработка событий.
Но с точки зрения программиста, вы начинаете с одного потока, называемого основным потоком.
Этот поток имеет возможность создавать дополнительные потоки.
Вопрос в том, как мы можем создать, запустить и выполнить поток?
В Java каждый поток представлен экземпляром класса Thread.
Создать поток, или экземпляр Thread, можно двумя способами.
Первый способ, это сначала создать объект Runnable.
Интерфейс Runnable определяет один метод run, предназначенный для того, чтобы содержать код, выполняемый в потоке.
После создания, объект Runnable передается конструктору класса Thread.
И поток запускается методом start.
Второй способ, это создать подкласс класса Thread.
Сам класс Thread реализует интерфейс Runnable, и при этом его метод run пустой.
Поэтому нужно создать подкласс класса Thread и предоставить собственную реализацию метода run.