Многопоточность

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

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

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

Жизненный цикл потока

Давайте подробно рассмотрим жизненный цикл потока.

  • Новый (New) Созданный поток находится в состоянии "новый", в котором остается до начала работы.
  • Исполняемый (Runnable) После того, как поток начал свою работу, он становится исполняемым (runnable). Это означает, что данный поток выполняет какую-то работу.
  • Ожидающий (Waiting) Временами поток не может выполнять свою работу, например, ожидает другой поток, который выполняет определенные вычисления. Поток находится в состоянии ожидания до момента, когда получит определенный сигнал, например о том, что все необходимые вычисления выполнены.
  • Временно ожидающий (Timed waiting) Мы можем задать потоку определенное время ожидания, по истечении которого он продолжит свою работу.
  • Остановленный (Terminated) После того, как поток выполнит свою работу, он переходит в состояние остановленный (прекращенный).

Свойства потока

Каждый поток имеет конкретный приоритет, который помогает операционной системе (далее – ОС) определять, в каком именно порядке имеющиеся потоки должны быть запущены.

Приоритет потоков варьируется от минимального (MIN_PRIORITY – 1) до максимального (MAX_PRIORITY – 10). По умолчанию, все потоки создаются с нормальным приоритетом (NORM_PRIORITY – 5) .

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

Создание потока с помощью интерфейса Runnable

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

Стоит отметить, что класс, в котором мы хотим использовать многопоточность, должен имплементировать интерфейс Runnable.

Пример.

Класс ThreadByRunnable:

public class ThreadByRunnable implements Runnable {
    private Thread thread;
    private String threadName;

    public ThreadByRunnable(String threadName) {
        this.threadName = threadName;
        System.out.println("Thread " + threadName + " created successfully.");
    }

    @Override
    public void run() {
        System.out.println("Thread " + threadName + " is running...");

        try {


            for (int i = 1; i 
<
= 5; i++) {
                System.out.println("Thread " + threadName + " " + i);
                Thread.sleep(100);
            }
        }catch (InterruptedException e){
            System.out.println("Thread " + threadName + " interrupted.");
            e.printStackTrace();
        }

        System.out.println("Leaving thread " + threadName);
    }

    public void start() {
        System.out.println("Thread " + threadName + " is started successfully.");
        if(thread == null){
         thread = new Thread(this, threadName);
            thread.start();
        }
    }
}

Класс MultithreadingDemo:

public class MultithreadingDemo {
    public static void main(String[] args) {
        ThreadByRunnable threadOne = new ThreadByRunnable("ThreadOne");
        ThreadByRunnable threadTwo = new ThreadByRunnable("ThreadTwo");

        threadOne.start();
        threadTwo.start();
    }
}

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

/*Some System Messages*/

Thread ThreadOne created successfully.
Thread ThreadTwo created successfully.
Thread ThreadOne is started successfully.
Thread ThreadTwo is started successfully.
Thread ThreadOne is running...
Thread ThreadOne 1
Thread ThreadTwo is running...
Thread ThreadTwo 1
Thread ThreadOne 2
Thread ThreadTwo 2
Thread ThreadOne 3
Thread ThreadTwo 3
Thread ThreadOne 4
Thread ThreadTwo 4
Thread ThreadOne 5
Thread ThreadTwo 5
Leaving thread ThreadOne
Leaving thread ThreadTwo

Создание потока с помощью класса Thread

Второй способ создания потока – наследование класса Thread. Благодаря методам класса Thread этот способ дает нам больше гибкости при работе с потоками.

Рассмотрим пример простого приложения.

Пример:

Класс ThreadByExtending

public class ThreadByExtending extends Thread{
    private Thread thread;
    private String threadName;

    public ThreadByExtending(String threadName) {
        this.threadName = threadName;
        System.out.println("Thread " + threadName + " created successfully.");
    }

    public void run(){
        System.out.println("Thread " +  threadName + " is running...");

        try {
            for(int i = 1;i
<
=5; i++){
                System.out.println("Thread " + threadName + " " + i);
                Thread.sleep(100);
            }
        }catch (InterruptedException e){
            System.out.println("Thread " + threadName + " is interrupted.");
            e.printStackTrace();
        }
        System.out.println("Leaving thread " + threadName);
    }

    public void start(){
        System.out.println("Thread " + threadName + " is started successfully.");
        if(thread == null){
            thread = new Thread(this,threadName);
            thread.start();
        }
    }
}

Класс ThreadByExtendingDemo

public class ThreadByExtendingDemo {
    public static void main(String[] args) {
        ThreadByExtending threadOne = new ThreadByExtending("Thread One");
        ThreadByExtending threadTwo = new ThreadByExtending("Thread Two");

        threadOne.start();
        threadTwo.start();
    }
}

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

/*Some System Messages*/

Thread Thread One created successfully.
Thread Thread Two created successfully.
Thread Thread One is started successfully.
Thread Thread Two is started successfully.
Thread Thread One is running...
Thread Thread One 1
Thread Thread Two is running...
Thread Thread Two 1
Thread Thread One 2
Thread Thread Two 2
Thread Thread One 3
Thread Thread Two 3
Thread Thread One 4
Thread Thread Two 4
Thread Thread One 5
Thread Thread Two 5
Leaving thread Thread One
Leaving thread Thread Two

С конструкторами и методами класса Thread вы можете ознакомиться в официальной документации.


Синхронизация потока

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

Например, несколькими потоками пытаются внести изменения в один и тот же текстовый файл. В результате этого данные могут быть повреждены, так как один поток пытается записать данные “поверх” данных второго потока.

Для предотвращения таких ситуаций применяется синхронизация.

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

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

ССЫЛКА НА ПРИМЕР.


Основные операции с потоками

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

Рассмотрим пример простого приложения.

ССЫЛКА НА ПРИМЕР


Взаимодейтсвие потоков

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

Для обеспечения этого процесса применяются следующие методы:

  • public void wait() Этот метод переводит поток в режим ожидания до момента вызова метода notify()
  • public void notify() Этот метод переводит один поток из режима ожидания в активный режим.
  • public void notifyAll() Этот метод переводит все потоки, которые находятся в режиме ожидания, в активный режим.

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

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

ССЫЛКА НА ПРИМЕР.


Взаимная блокировка потоков

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

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

ССЫЛКА НАПРИМЕР.

results matching ""

    No results matching ""