Java. Средства языка Java для работы с потоками

Средства языка Java для работы с потоками выполнения. Класс Thread. Интерфейс Runnable. Главный поток выполнения. Создание дочернего потока


Содержание


Поиск на других ресурсах:




1. Способы создания потоков выполнения

В языке Java поток выполнения можно создавать одним из двух способов:

  • путем расширения класса Thread. Этот класс является основным классом, на котором построена многопоточная система Java. Класс Thread определяет один поток выполнения. Если в программе нужно создать три потока выполнения, то, соответственно, создается три экземпляра класса Thread;
  • за счет реализации интерфейса Runnable. Интерфейс Runnable дополняет возможности класса Thread.

 

2. Класc Thread. Конструкторы. Обзор методов

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

Thread(Runnable threadObject)
Thread(Runnable threadObject, String threadName)

здесь

  • threadObject – объект некоторого класса, который нужно выполнить в потоке. Этот объект должен реализовывать интерфейс Runnable (смотрите ниже) или расширять класс Thread;
  • threadName – имя, которое устанавливается для созданного потока исполнения. Это имя может быть прочитано методом getName().

В общем случае, код создания потока выполнения с именем «My thread» для объекта класса MyThreadClass выглядит следующим образом:

...
// Создать экземпляр класса MyThreadClass
MyThreadClass threadObject = new MyThreadClass();

// Создать дочерний поток в главном потоке
Thread thr = new Thread(threadObject, "My thread");
...

Класс Thread содержит ряд методов для работы с потоками выполнения. Ниже приведено описание этих методов в классе:

  • getName() — получить имя потока выполнения;
  • getPriority() — получить приоритет потока выполнения;
  • isAlive() — определить, выполняется ли поток;
  • join() — предназначен для ожидания завершения потока выполнения;
  • run() — задает код, который должен выполняться в потоке выполнения. Это есть точка входа в поток;
  • sleep() — приостанавливает выполнение вызывающего потока выполнения на указанное время;
  • start() — запускает поток выполнения с помощью вызова метода run().

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

 

3. Интерфейс Runnable. Особенности использования

Интерфейс Runnable используется для создания потока выполнения. Поток выполнения можно создать из объекта класса, реализующего интерфейс Runnable.

Интерфейс объявляет один метод run(), который имеет следующую общую форму:

public abstract void run();

Методом run() определяется точка входа в поток. Как только завершится выполнение метода run(), завершится и выполнения потока. В методе run() можно выполнять любые операции, присущие обычным методам (объявлять переменные, использовать классы, вызывать другие методы и т.д.).

В общем случае, создание потока выполнения для класса MyThreadClass выглядит следующим образом:

class MyThreadClass implements Runnable {

  // ...

  public void run() {
    // Программный код, который выполняется в потоке
    // ...
  }
}

 

4. Главный поток выполнения. Особенности. Доступ к главному потоку выполнения

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

  • главный поток начинает выполняться первым;
  • из главного потока можно породить (создать) все дочерние потоки;
  • желательно, чтобы главный поток завершался последним и выполнял некоторые завершающие действия при закрытии программы.

Чтобы получить доступ к главному потоку управления, нужно создать экземпляр класса Thread с помощью вызова статического метода currentThread(). После этого, с помощью экземпляра, можно использовать дополнительные функции управления главным потоком (приостановить главный поток, получить информацию о главном потоке и т.д.).

 

5. Пример, демонстрирующий доступ к главному потоку выполнения

В примере продемонстрирован доступ к главному потоку в программе и его использование.

public class TrainThreads {

  public static void main(String[] args) {

    // Получить данные о главном потоке выполнения

    // 1. Получить объект главного потока
    Thread thr = Thread.currentThread();

    // 2. Вывести данные о текущем потоке выполнения
    System.out.println("Current thread: " + thr);

    // 3. Установить новое имя потока выполнения
    thr.setName("MY THREAD");

    // 4. Повторно вывести данные о потоке выполнения
    System.out.println("Current thread: " + thr);

    // 5. Продемонстрировать работу потока выполнения
    try {
      for (int n=5; n>0; n--) {
        System.out.println(n);
        Thread.sleep(1000); // остановить выполнение потока на 1 секунду
      }
    }
    catch (InterruptedException e) {
      System.out.println("The main thread is interrupted.");
    }
  }
}

Результат выполнения программы

Current thread: Thread[main,5,main]
Current thread: Thread[MY THREAD,5,main]
5
4
3
2
1

 

6. Пример, демонстрирующий создание дочернего потока путем реализации интерфейса Runnable

Одним из способов создания дочернего потока является реализация интерфейса Runnable. Если класс использует интерфейс Runnable, то в этом классе нужно реализовывать метод run().

// Пример создания потока с помощью реализации интерфейса Runnable
// В интерфейсе Runnable определен метод run(), который нужно реализовать
class MyThread implements Runnable {

  Thread thr; // ссылка на текущий поток выполнения

    // Конструктор класса. В конструкторе нужно создать поток
    MyThread() {
      // создать новый поток
      thr = new Thread(this, "Thread: MyThread");
      System.out.println("Дочерний поток создан.");
      thr.start(); // запустить поток
    }

    // Реализация метода run() из интерфейса Runnable
    public void run() {
      try {
        for (int i=10; i>0; i--) {
          System.out.println("Дочерний поток: " + i);
          Thread.sleep(500);
        }
      }
      catch (InterruptedException e) {
        System.out.println("Дочерний поток прерван.");
      }
      System.out.println("Дочерний поток завершен.");
    }
  }

  public class TrainThreads {

    public static void main(String[] args) {
      // Демонстрация работы дочернего потока
      new MyThread(); // создать новый поток

      try {
        for (int i=10; i>0; i--) {
          System.out.println("Главный поток: " + i);
          Thread.sleep(1000);
        }
      }
      catch (InterruptedException e) {
        System.out.println("Главный поток прерван.");
      }
      System.out.println("Главный поток завершен.");
    }
  }

Результат выполнения программы

Дочерний поток создан.
Главный поток: 10
Дочерний поток: 10
Дочерний поток: 9
Главный поток: 9
Дочерний поток: 8
Дочерний поток: 7
Дочерний поток: 6
Главный поток: 8
Дочерний поток: 5
Главный поток: 7
Дочерний поток: 4
Дочерний поток: 3
Главный поток: 6
Дочерний поток: 2
Дочерний поток: 1
Главный поток: 5
Дочерний поток завершен.
Главный поток: 4
Главный поток: 3
Главный поток: 2
Главный поток: 1
Главный поток завершен.

 

7. Пример, демонстрирующий создание дочернего потока путем расширения класса Thread

Другой способ создания потока — наследование (расширение) класса Thread. При этом способе доступны некоторые методы суперкласса Thread. Более подробно об использовании методов класса Thread описывается здесь.

// Создание дочернего потока с помощью расширения класса Thread
class MyThread extends Thread {

  // Конструктор
  public MyThread() {
    // создать новый поток выполнения
    super("Демонстрационный поток");
    System.out.println("Дочерний поток.");
    start();
  }

  // Реализация собственного метода run(), в этом методе
  // указываются действия (работа), которые выполняет наш поток
  public void run() {
    try {
      for (int i=10; i>0; i--) {
        System.out.println("Дочерний поток: " + i);
        Thread.sleep(500);
      }
    }
    catch (InterruptedException e) {
      System.out.println("Дочерний поток прерван.");
    }
    System.out.println("Дочерний поток завершен.");
  }
}

public class TrainThreads {

  public static void main(String[] args) {

    // Демонстрация создания потока
    new MyThread(); // создать дочерний поток

    try {
      for (int i=10; i>0; i--) {
        System.out.println("Главный поток: " + i);
        Thread.sleep(1000);
      }
    }
    catch (InterruptedException e) {
      System.out.println("Главный поток прерван:");
    }
    System.out.println("Главный поток завершен.");
  }
}

Результат выполнения программы

Дочерний поток создан.
Дочерний поток: 10
Главный поток: 10
Дочерний поток: 9
Главный поток: 9
Дочерний поток: 8
Дочерний поток: 7
Дочерний поток: 6
Главный поток: 8
Дочерний поток: 5
Дочерний поток: 4
Главный поток: 7
Дочерний поток: 3
Дочерний поток: 2
Главный поток: 6
Дочерний поток: 1
Главный поток: 5
Дочерний поток завершен.
Главный поток: 4
Главный поток: 3
Главный поток: 2
Главный поток: 1
Главный поток завершен.

 


Связанные темы