Любое приложение, которое вы запускаете, есть некий процесс.
У него собственный набор ресурсов и собственный участок памяти, к которым не могут обращаться другие процессы.
Если это приложение хочет обратиться к другим приложениям, например сервер который запускается на нескольких компьютерах это многопроцессное приложение, и чтобы это сделать им нужно общаться через внешние ресурсы(например писать и читать в файл или общение через базу).
Многопроцессное приложение можно запускать на несколких компьютерах.
Потоки не являются отдельным приложением. Потоки живут внутри какого то приложения, они живут в одном процессе.
У каждого процесса есть как минимум один поток - это главный поток исполнения (main). Кроме главного потока у процесса могут быть еще несколько других потоков.
В отличие от процессов, потоки делят между собой память и другие ресурсы приложения в котором они запущены. Если у вас процесс и у процесса память и в процессе два потока, они смогут через этот heap между собой передавать какие то данные. Это значит что есть объект в хипе на который есть ссылка из стеков двух потоков и в процессе работы из двух этих потоков по ссылке можно к этому объекту обратиться.
Потоки могут порождать другие потоки и взаимодействовать с ними.
Это объект, у класса которого есть методы start() и run().
При вызове метода start() через какое то время, которое вы не которолируете, операционная система позовет у этого объекта метод run(). Если точнее, операционная система создаст условия, при которых начнется выполнение команд внутри метода run(). Это выполнение начнется в параллель метода main или каких то других методов run() других потоков.
Но создавая потоки, мы не получаем от операционной системы гарантии последовательности исполнения методов run(). Вы вызываете только методы start(), а в какой момент запустятся методы run() вы не которолируете.
Можно в своем приложении создать некий набор команд для операционной системы попросив ее сделать какие то вещи связанные с потоками.
Сам процесс создания потока, переключение между потоками, какой именно из потоков будет исполнен на каком процессоре решает операционная система.
Также операционная система предоставляет некое API, в котором можно попросить создать и сделать некое уведомление. На основе чего можно запускать поток по получении какого либо события, как и пробуждение потока.
Создать класс, который будет являться объектом потока.
Есть 3 возможности:
Runnable и определяет метод run().
При создании объекта класса Thread передать в него объект класса Runnable и вызвать метод start().public class HelloRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String[] args) {
new Thread(new HelloRunnable()).start();
}
}Thread и от объекта самого этого класса вызвать start().public class HelloThread extends Thread {
@Override
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String[] args) {
new HelloThread().start();
}
}public class HelloThread {
public static void main(String[] args) {
new Thread(() ->
System.out.println("Hello from a thread!")
).start();
}
}И для Runnable и для Thread можно получить ссылку на объект текущего потока через статический метод Thread thread = Thread.currentThread().
long getId()
у каждого потока есть id
int getPriority()void setPriority(int priority)
у каждого потока есть приоритет по которому операционная система решает как много ресурсов каждому потоку нужно выдавать.
static void sleep(long ms)
Если нужно остановить выполнение потока на определенное время
Thread.sleep(1000) - остановит выполнение потока на 1 секунду(он не проснется раньше, но через сколько точно он проснется решает операционная система)
void interrupt()static boolean interrupted()
Возможность разбудить поток.
Сам поток проснется через определенное время. Но мы можем разбдить его например из другого потока. Это происходит через выброс исключения InterupptedException - это в случае если поток например спит, а если не спит то будет проставлен флаг Thread.interrupted() = true. И поток сам должен проверить не установил ли его кто-нибудт в true, чтобы прервать работу.
void join()
Если надо остановить поток до окончания выполнения другого.
Если join позвать на ссылке объекта некого потока, то вы остановите текущий поток до тех пор пока не завершится тот у которого вы join позвали.