Процессы, потоки и приоритеты. Что такое многопоточность. Работа с потоками в java

Чтобы создать поток вычислений в Jаvа-программе, следует начать с конструирования объекта класса Thread:

Thread worker = new Thread();

После того как объект Thread создан, его можно настроить и запустить на выполнение. Настройка потока включает в себя задание исходного приоритета выполнения, имени и Т.д. Когда объект готов к работе, вызывается его метод start. Метод start, используя данные объекта Thread, порождает новый поток Вычислений и завершает свое выполнение. Далее виртуальная машина Java вызывает метод run объекта и делает поток активным. Вызов start для каждого потока может быть осуществлен только один раз – повторное обращение приводит к выбрасыванию исключения типа i11ega1ThreadStateException.

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

Стандартная реализация метода Thread . run не предполагает выполнения каких бы то ни было действий. Чтобы заставить поток делать что-нибудь полезное, необходимо либо расширить класс Thread и предложить собственную пере

определенную версию метода гип, либо создать объект класса, производного от Runnable, и передать его конструктору потока в качестве аргумента. Сначала мы рассмотрим первый подход, связанный с расширением класса Thread. Вопросам использования объектов Runnablе посвящен следующий раздел.

Ниже приведен пример простой программы, предусматривающей создание двух потоков, которые выводят на экран слова "ping" и "PONG" с различной частотой.

public class РingPong extends Thread {

private String word; // Слово, подлежащее выводу на экран

private int delay; // величина временной задержки

public РingPong(String whatToSay, int delayTime) {

word = whatToSay;

delay = delayTime;

public void run() {

system.out.print(word + Thread.sleep(delay);

} catch (InterruptedException e)

return; // Завершить поток

Public static void main(Stringargs){

new PingPong(“ping”,33).start();

new PingPong(“ping”,100).start();

Мы определили новый класс РingPong, Производный от Thread. Метод гип содержит бесконечный цикл, в котором выполняются инструкции вывода слова word на экран и приостановки действия потока на период времени, заданный значением delay. Метод РingPong. гип не способен генерировать исключения, поскольку Никакие исключения не указаны в объявлении унаследованного метода Thread. тип. Тем не менее мы должны предусмотреть средства обработки исключения типа InterruptedException, которое может быть выброшено методом slеер (об исключении InterruptedException речь пойдет позже).

Теперь ничего не, мешает создать несколько потоков, и метод main – как раз то место, где можно это сделать. Мы создаем два объекта РingPong, передавая конструктору класса различные аргументы, представляющие слово и интервал задержки, и вызываем для каждого объекта метод start. Потоки активизируются и начинают выполняться. Вот как могут выглядеть результаты их работы:

ping PONG ping ping PONG ping ping ping PONG ping

ping PONG ping ping ping PONG ping ping PONG ping

pong ping PONG ping ping PONG ping ping ping PONG

plng ping PONG ping ping ping PONG ping ping PONG

ping ping ping PONG ping ping PONG ping ping ping

PONG ping ping PONG ping ping ping PONG ping ping

Потоку разрешено присвоить имя – либо с помощью аргумента String, передаваемого конструктору, либо посредством вызова метода setName. Текущее значение имени потока легко получить с помощью метода getName. Имена потоков служат только для удобства программиста (исполняющей системой они не используются) но поток должен обладать именем, и если оно не задано, исполняющая система принимает эту обязанность на себя, генерируя имена в соответствии с некоторым простым правилом, например thread_1, thread_2 и Т.д.

ссылку на объект Thread текущего выполняемого потока можно получить с помощью статического метода Thread. currentThread. Во время работы программы текущий. поток существует всегда, даже если вы не создавали Потоки явно – метод main активизируется с помощью потока, создаваемого исполняющей системой.

Упражнение 0.1. Напишите про грамму, которая отображает имя потока, выполняющего код метода main.

6 ответов

Существует ровно один способ создать новый поток в Java и создать экземпляр java.lang.Thread (чтобы запустить этот поток, вам также нужно позвонить start()).

Все остальное, что создает потоки в Java-коде, возвращается к этому одному пути за крышкой (например, реализация ThreadFactory будет создавать экземпляры объектов Thread в какой-то момент,...).

Существует два разных способа указать, какой код следует запускать в этом потоке:

  • Внедрите интерфейс java.lang.Runnable и передайте экземпляр класса, реализующего его, в конструктор Thread .
  • Расширьте Thread и переопределите его метод run() .

Первый подход (реализация Runnable) обычно считается более правильным, потому что вы обычно не создаете новый "вид" Thread, но просто хотите запустить некоторый код (т.е. a Runnable) в выделенный поток.

Темы могут быть созданы главным образом тремя различными способами.

  • Расширить java.lang. Тема класс
class SampleThread extends Thread { //method where the thread execution will start public void run(){ //logic to execute in a thread } //let’s see how to start the threads public static void main(String args){ Thread t1 = new SampleThread(); Thread t2 = new SampleThread(); t1.start(); //start the first thread. This calls the run() method. t2.start(); //this starts the 2nd thread. This calls the run() method. } }
  1. Внедрить интерфейс java.lang. Runnable
class A implements Runnable{ @Override public void run() { // implement run method here } public static void main() { final A obj = new A(); Thread t1 = new Thread(new A()); t1.start(); } }
  1. Внедрить интерфейс java.util.concurrent. Callable
class Counter implements Callable { private static final int THREAD_POOL_SIZE = 2; // method where the thread execution takes place public String call() { return Thread.currentThread().getName() + " executing ..."; } public static void main(String args) throws InterruptedException, ExecutionException { // create a pool of 2 threads ExecutorService executor = Executors .newFixedThreadPool(THREAD_POOL_SIZE); Future future1 = executor.submit(new Counter()); Future future2 = executor.submit(new Counter()); System.out.println(Thread.currentThread().getName() + " executing ..."); //asynchronously get from the worker threads System.out.println(future1.get()); System.out.println(future2.get()); } }

Использовать интерфейс Callable с инфраструктурой Executor для объединения потоков.

Интерфейс Runnable или Callable предпочтительнее расширения класса Thread

Есть только два способа создания потока, о котором вы уже упоминали, но третий способ - вызвать Thread.

В java1.5 есть еще один способ вызвать поток. То есть "Исполнительная служба". Все эти классы взяты из пакета java.util.concurrent. Существуют различные способы создания "ExecutorService" с использованием класса "Исполнители" factory. Ниже приведен один из способов создания "ExecutorService" .

ExecutorService es = Executors.newSingleThreadExecutor();

RunnableImpl r = new RunnableImpl();

Будущее fu = es.submit(r);

Используя методы "ExecutorService" , мы можем отправить истребителю Runnable или Callable в службу для выполнения.

Как бы то ни было, это невозможно назвать новым способом создания Thread. Это связано с тем, что ExecutorService внутренне использует класс ThreadFactory для создания нового потока, который внутренне использует истребитель первого или второго метода. Поэтому мы должны сказать, что есть только два способа создания потоков, но есть новый способ в java1.5 для вызова потока, но не для создания потока.

Any application can have multiple processes (instances). Each of this process can be assigned either as a single thread or multiple threads.

We will see in this tutorial how to perform multiple tasks at the same time and also learn more about threads and synchronization between threads.

In this tutorial, we will learn-

What is Single Thread?

A single thread is basically a lightweight and the smallest unit of processing. Java uses threads by using a "Thread Class".

There are two types of thread – user thread and daemon thread (daemon threads are used when we want to clean the application and are used in the background).

When an application first begins, user thread is created. Post that, we can create many user threads and daemon threads.

Single Thread Example:

Package demotest; public class GuruThread { public static void main(String args) { System.out.println("Single Thread"); } }

Advantages of single thread:

  • Reduces overhead in the application as single thread execute in the system
  • Also, it reduces the maintenance cost of the application.

What is Multithreading?

Multithreading in java is a process of executing two or more threads simultaneously to maximum utilization of CPU.

Multithreaded applications are where two or more threads run concurrently; hence it is also known as Concurrency in Java. This multitasking is done, when multiple processes share common resources like CPU, memory, etc.

Each thread runs parallel to each other. Threads don"t allocate separate memory area; hence it saves memory. Also, context switching between threads takes less time.

Example of Multi thread:

Package demotest; public class GuruThread1 implements Runnable { public static void main(String args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public void run() { } }

Advantages of multithread:

  • The users are not blocked because threads are independent, and we can perform multiple operations at times
  • As such the threads are independent, the other threads won"t get affected if one thread meets an exception.

Thread Life Cycle in Java

The Lifecycle of a thread:

There are various stages of life cycle of thread as shown in above diagram:

  1. Runnable
  2. Running
  3. Waiting
  1. New: In this phase, the thread is created using class "Thread class".It remains in this state till the program starts the thread. It is also known as born thread.
  2. Runnable: In this page, the instance of the thread is invoked with a start method. The thread control is given to scheduler to finish the execution. It depends on the scheduler, whether to run the thread.
  3. Running: When the thread starts executing, then the state is changed to "running" state. The scheduler selects one thread from the thread pool, and it starts executing in the application.
  4. Waiting: This is the state when a thread has to wait. As there multiple threads are running in the application, there is a need for synchronization between threads. Hence, one thread has to wait, till the other thread gets executed. Therefore, this state is referred as waiting state.
  5. Dead: This is the state when the thread is terminated. The thread is in running state and as soon as it completed processing it is in "dead state".

Some of the commonly used methods for threads are:

Method Description
start() This method starts the execution of the thread and JVM calls the run() method on the thread.
Sleep(int milliseconds) This method makes the thread sleep hence the thread"s execution will pause for milliseconds provided and after that, again the thread starts executing. This help in synchronization of the threads.
getName() It returns the name of the thread.
setPriority(int newpriority) It changes the priority of the thread.
yield () It causes current thread on halt and other threads to execute.

Example: In this example we are going to create a thread and explore built-in methods available for threads.

Package demotest; public class thread_example1 implements Runnable { @Override public void run() { } public static void main(String args) { Thread guruthread1 = new Thread(); guruthread1.start(); try { guruthread1.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } guruthread1.setPriority(1); int gurupriority = guruthread1.getPriority(); System.out.println(gurupriority); System.out.println("Thread Running"); } }

Explanation of the code:

Code Line 2: We are creating a class "thread_Example1" which is implementing the Runnable interface (it should be implemented by any class whose instances are intended to be executed by the thread.)

Code Line 4: It overrides run method of the runnable interface as it is mandatory to override that method

Code Line 6: Here we have defined the main method in which we will start the execution of the thread.

Code Line 7: Here we are creating a new thread name as "guruthread1" by instantiating a new class of thread.

Code Line 8: we will use "start" method of the thread using "guruthread1" instance. Here the thread will start executing.

Code Line 10: Here we are using the "sleep" method of the thread using "guruthread1" instance. Hence, the thread will sleep for 1000 milliseconds.

Code 9-14: Here we have put sleep method in try catch block as there is checked exception which occurs i.e. Interrupted exception.

Code Line 15: Here we are setting the priority of the thread to 1 from whichever priority it was

Code Line 16: Here we are getting the priority of the thread using getPriority()

Code Line 17: Here we are printing the value fetched from getPriority

Code Line 18: Here we are writing a text that thread is running.

5 is the Thread priority, and Thread Running is the text which is the output of our code.

Java Thread Synchronization

In multithreading, there is the asynchronous behavior of the programs. If one thread is writing some data and another thread which is reading data at the same time, might create inconsistency in the application.

When there is a need to access the shared resources by two or more threads, then synchronization approach is utilized.

Java has provided synchronized methods to implement synchronized behavior.

In this approach, once the thread reaches inside the synchronized block, then no other thread can call that method on the same object. All threads have to wait till that thread finishes the synchronized block and comes out of that.

In this way, the synchronization helps in a multithreaded application. One thread has to wait till other thread finishes its execution only then the other threads are allowed for execution.

It can be written in the following form:

Synchronized(object) { //Block of statements to be synchronized }

Java Multithreading Example

In this example, we will take two threads and fetch the names of the thread.

Example1:

GuruThread1.java package demotest; public class GuruThread1 implements Runnable{ /** * @param args */ public static void main(String args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public void run() { } }

Explanation of the code:

Code Line 3: We have taken a class "GuruThread1" which implements Runnable (it should be implemented by any class whose instances are intended to be executed by the thread.)

Code Line 8: This is the main method of the class

Code Line 9: Here we are instantiating the Thread class and creating an instance named as "guruThread1" and creating a thread.

Code Line 10: Here we are instantiating the Thread class and creating an instance named a "guruThread2" and creating a thread.

Code Line 11: We are starting the thread i.e. guruThread1.

Code Line 12: We are starting the thread i.e. guruThread2.

Code Line 13: Outputting the text as "Thread names are following:"

Code Line 14: Getting the name of thread 1 using method getName() of the thread class.

Code Line 15: Getting the name of thread 2 using method getName() of the thread class.

When you execute the above code, you get the following output:

Thread names are being outputted here as

  • Guru1
  • Guru2

Example 2:

In this example, we will learn about overriding methods run() and start() method of a runnable interface and create two threads of that class and run them accordingly.

Also, we are taking two classes,

  • One which will implement the runnable interface and
  • Another one which will have the main method and execute accordingly.
package demotest; public class GuruThread2 { public static void main(String args) { // TODO Auto-generated method stub GuruThread3 threadguru1 = new GuruThread3("guru1"); threadguru1.start(); GuruThread3 threadguru2 = new GuruThread3("guru2"); threadguru2.start(); } } class GuruThread3 implements Runnable { Thread guruthread; private String guruname; GuruThread3(String name) { guruname = name; } @Override public void run() { System.out.println("Thread running" + guruname); for (int i = 0; i < 4; i++) { System.out.println(i); System.out.println(guruname); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Thread has been interrupted"); } } } public void start() { System.out.println("Thread started"); if (guruthread == null) { guruthread = new Thread(this, guruname); guruthread.start(); } } }

Explanation of the code:

Code Line 2: Here we are taking a class "GuruThread2" which will have the main method in it.

Code Line 4: Here we are taking a main method of the class.

Code Line 6-7: Here we are creating an instance of class GuruThread3 (which is created in below lines of the code) as "threadguru1" and we are starting the thread.

Code Line 8-9: Here we are creating another instance of class GuruThread3 (which is created in below lines of the code) as "threadguru2" and we are starting the thread.

Code Line 11: Here we are creating a class "GuruThread3" which is implementing the runnable interface (it should be implemented by any class whose instances are intended to be executed by the thread.)

Code Line 13-14: we are taking two class variables from which one is of the type thread class and other of the string class.

Code Line 15-18: we are overriding the GuruThread3 constructor, which takes one argument as string type (which is threads name) that gets assigned to class variable guruname and hence the name of the thread is stored.

Code Line 20: Here we are overriding the run() method of the runnable interface.

Code Line 21: We are outputting the thread name using println statement.

Code Line 22-31: Here we are using a for loop with counter initialized to 0, and it should not be less than 4 (we can take any number hence here loop will run 4 times) and incrementing the counter. We are printing the thread name and also making the thread sleep for 1000 milliseconds within a try-catch block as sleep method raised checked exception.

Code Line 33: Here we are overriding start method of the runnable interface.

Code Line 35: We are outputting the text "Thread started".

Code Line 36-40: Here we are taking an if condition to check whether class variable guruthread has value in it or no. If its null then we are creating an instance using thread class which takes the name as a parameter (value for which was assigned in the constructor). After which the thread is started using start() method.

When you execute the above code you get the following output:

There are two threads hence, we get two times message "Thread started".

We get the names of the thread as we have outputted them.

It goes into for loop where we are printing the counter and thread name and counter starts with 0.

The loop executes three times and in between the thread is slept for 1000 milliseconds.

Hence, first, we get guru1 then guru2 then again guru2 because the thread sleeps here for 1000 milliseconds and then next guru1 and again guru1, thread sleeps for 1000 milliseconds, so we get guru2 and then guru1.

Summary :

In this tutorial, we saw multithreaded applications in Java and how to use single and multi threads.

  • In multithreading, users are not blocked as threads are independent and can perform multiple operations at time
  • Various stages of life cycle of the thread are,
    • Runnable
    • Running
    • Waiting
  • We also learned about synchronization between threads, which help the application to run smoothly.
  • Multithreading makes many more application tasks easier.
03.10.17 8.3K

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

Пример одного потока :

package demotest; public class GuruThread1 implements Runnable { /** * @param args */ public static void main(String args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public void run() { } }

Преимущества одного потока :

  • При выполнении одного потока снижается нагрузка на приложение;
  • Уменьшается стоимость обслуживания приложения.

Что такое многопоточность?

Многопоточность в Java - это выполнение двух или более потоков одновременно для максимального использования центрального процесса.

Многопоточные приложения - это приложения, где параллельно выполняются два или более потоков. Данное понятие известно в Java как многопотоковое выполнение. При этом несколько процессов используют общие ресурсы, такие как центральный процессор, память и т. д.

Все потоки выполняются параллельно друг другу. Для каждого отдельного потока не выделяется память, что приводит к ее экономии. Кроме этого переключение между потоками занимает меньше времени.

Пример многопоточности :

package demotest; public class GuruMultithread implements Runnable{ /** * @param args */ public static void main(String args) { Thread guruthread1 = new Thread(); guruThread1.start(); Thread guruthread2 = new Thread(); guruThread2.start(); } @Override public void run() { // TODO Автоматически сгенерированный метод stub } }

Преимущества многопоточности :

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

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

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


Стадии жизни потока :
  1. Новый;
  2. Готовый к выполнению;
  3. Выполняемый;
  4. Ожидающий;
  5. Остановленный.
  1. Новый : в этой фазе поток создается с помощью класса Thread . Он остается в этом состоянии, пока программа его не запустит;
  2. Готовый к выполнению : экземпляр потока вызывается с помощью метода Start . Управление потоком предоставляется планировщику для завершения выполнения. От планировщика зависит то, следует ли запускать поток;
  3. Выполняемый : с началом выполнения потока его состояние изменяется на «выполняемый ». Планировщик выбирает один поток из пула потоков и начинает его выполнение в приложении;
  4. Ожидающий : поток ожидает своего выполнения. Поскольку в приложении выполняется сразу несколько потоков, необходимо синхронизировать их. Следовательно, один поток должен ожидать, пока другой поток не будет выполнен. Таким образом, это состояние называется состоянием ожидания;
  5. Остановленный : выполняемый поток после завершения процесса переходит в состояние «остановленный », известное также как «мертвый ».

Часто используемые методы для управления многопоточностью Java :

Например : В этом примере создается поток, и применяются перечисленные выше методы.

package demotest; public class thread_example1 implements Runnable { @Override public void run() { } public static void main(String args) { Thread guruthread1 = new Thread(); guruThread1.start(); try { guruthread1.sleep(1000); } catch (InterruptedException e) { // TODO Автоматически сгенерированный блок catch e.printStackTrace(); } guruthread1.setPriority(1); int gurupriority = guruthread1.getPriority(); System.out.println(gurupriority); System.out.println("Thread Running"); } }

Объяснение кода

Строка кода 2 : создаем класс «thread_Example1 Runnable » (готовый к выполнению ). Он должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком.
Строка 4 : переопределяется метод run для готового к запуску интерфейса, так как он является обязательным при переопределении этого метода.
Строка кода 6 : определяется основной метод, в котором начнется выполнение потока.
Строка кода 7 : создается новое имя потока «guruthread1 «, инициализируя новый класс потока.
Код строка 8 : используется метод «Start » в экземпляре «guruthread1 «. Здесь поток начнет выполняться.
Строка 10 : используется метод «sleep » в экземпляре «guruthread1 «. Поток приостановит свое выполнение на 1000 миллисекунд.
Строки 9-14 : применяется метод «sleep » в блоке «try catch », так как есть проверяемое исключение «Interrupted exception ».
Строка кода 15 : для потока назначается приоритет «1 », независимо от того, каким приоритет был до этого.
Строка кода 16 : получаем приоритет потока с помощью getPriority() .
Строка кода 17 : значение, извлеченное из getPriority .
Строка кода 18 : пишем текст, что поток выполняется.

Вывод

5 - это приоритет потока, а «Thread Running » - текст, который является выводом нашего кода.

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

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

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

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

Это можно написать следующим образом:

Synchronized(object) { //Блок команд для синхронизации }

Пример многопоточности Java

В этом Java многопоточности примере мы задействуем два потока и извлекаем имена потоков.

Пример 1

GuruThread1.java package demotest; public class GuruThread1 implements Runnable{ /** * @param args */ public static void main(String args) { Thread guruThread1 = new Thread("Guru1"); Thread guruThread2 = new Thread("Guru2"); guruThread1.start(); guruThread2.start(); System.out.println("Thread names are following:"); System.out.println(guruThread1.getName()); System.out.println(guruThread2.getName()); } @Override public void run() { } }

Объяснение кода

Строка кода 3 : задействуем класс «GuruThread1 «, который реализует интерфейс «Runnable » (он должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком ).
Строка 8 : основной метод класса.
Строка 9 : создаем класс Thread , экземпляр с именем «guruThread1 » и поток.
Строка 10 : создаем класс Thread , экземпляр с именем «guruThread2 » и поток.
Строка 11 : запускаем поток guruThread1 .
Строка 12 : запускаем поток guruThread2 .
Строка 13 : выводим текст «Thread names are following: «.
Строка 14 : получаем имя потока 1, используя метод getName() класса thread .
Строка кода 15 : получаем имя потока 2, используя метод getName() класса thread .

Вывод

Имена потоков выводятся как:

  • Guru1
  • Guru2

Пример 2

Из этого Java многопоточности урока мы узнаем о переопределяющих методах Run () и методе Start () интерфейса runnable . Создадим два потока этого класса и выполним их.

Также мы задействуем два класса:

  • Один будет реализовывать интерфейс runnable ;
  • Другой — с методом main и будет выполняться.

package demotest; public class GuruThread2 { public static void main(String args) { // TODO Автоматически сгенерированный метод stub GuruThread3 threadguru1 = new GuruThread3("guru1"); threadguru1.start(); GuruThread3 threadguru2 = new GuruThread3("guru2"); threadguru2.start(); } } class GuruThread3 implements Runnable { Thread guruthread; private String guruname; GuruThread3(String name) { guruname = name; } @Override public void run() { System.out.println("Thread running" + guruname); for (int i = 0; i < 4; i++) { System.out.println(i); System.out.println(guruname); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Thread has been interrupted"); } } } public void start() { System.out.println("Thread started"); if (guruthread == null) { guruthread = new Thread(this, guruname); guruthread.start(); } } }

Объяснение кода

Строка кода 2 : принимаем класс «GuruThread2 «, содержащий метод main .
Строка 4 : принимаем основной метод класса.
Строки 6-7 : создаем экземпляр класса GuruThread3 (создается в строках внизу ) как «threadguru1 » и запускаем поток.
Строки 8-9 : создаем еще один экземпляр класса GuruThread3 (создается в строках внизу ) как «threadguru2 » и запускаем поток.
Строка 11 : для многопоточности Java создаем класс «GuruThread3 «, который реализует интерфейс «Runnable ». Он должен быть реализован любым классом, экземпляры которого предназначены для выполнения потоком.
Строки 13-14 : принимаем две переменные класса, из которых одна - потоковый класс, другая - строковый класс.
Строки 15-18 : переопределение конструктора GuruThread3 , который принимает один аргумент как тип String (являющийся именем потока ). Имя будет присвоено переменной класса guruname и сохраняется имя потока.
Строка 20 : переопределяется метод run() интерфейса runnable .
Строка 21 : выводится имя потока с использованием набора команд println .
Строки 22-31 : используется цикл «for » со счетчиком, инициализированным на «0 », который не должен быть меньше 4 . Выводится имя потока, а также выполняется приостановка потока на 1000 миллисекунд в блоке try-catch , поскольку метод sleep вызвал проверяемое исключение.
Строка 33 : переопределяется метод start интерфейса runnable .
Строка 35 : выводится текст «Thread started «.
Строки 36-40 : проверяем, содержит ли переменная класса guruthread значение. Если оно равно NULL , создается экземпляр класса thread . После этого запускается поток с использованием класса start() .

Языка программирования Java. И сегодня речь пойдет о многопоточности:

  • что такое многопоточность;
  • как ее реализовать;
  • как создать о остановить потоки выполнения.

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

Многопоточность — это свойство системы выполнять несколько вычислений одновременно, тем самым ускоряя процесс этого вычисления. Например, когда Вы играете в компьютерные игры, вы видите, что Ваш персонаж выполняет определенное действие, другие персонажи, анимация, звук. Это все отдельные потоки если говорить примитивно.

В языке Java есть стандартный класс, который реализует многопоточность: Thread, который имплементирует Runable интерфейс. Для того, чтобы реализовать многопоточность в своей программе нужно унаследовать свой класс от Thread или имплементировать интерфейс Runable. Нечто похожее мы делали, когда создавали свои классы исключения в статье о . Но это еще не все. В классе Thread есть метод run() и start() , которые созданы чтобы делать вычисления и запускать выполнение кода соответственно. То есть в методе run() мы пишем, что хотим выполнить, а когда вызываем метод start(), он автоматически запускает наш код в run. Вот такая многоходовочка)). Все гораздо проще, когда смотришь на код.

    package com.java ;

    Runnable {

    public int i = 0 ;

    public void run() {

    new Thread (myMultithread) .start () ; //третий!!! порядок потоков в методе вовсе не означает, что они выполняться в таком порядке

Результат работы программы может быть разным при каждом запуске:

Как я уже прокомментировал в коде: результат будет не всегда совпадать с порядком следования вызовов в коде. Это зависит от множества факторов. Можно выставить приоритетность потоков. Тогда у каждого потока будет свой приоритет и результат будет более предсказуем, но из опыта скажу, что даже это не гарантирует строгий порядок выполнения потоков по приоритетам:

    package com.java ;

    public class MyMultithreadClass implements Runnable { //создаем наш многопоточный класс имплементируя его от Runnable

    public int i = 0 ;

    public void run() { //делаем реализацию метода run

    // TODO Auto-generated method stub

    MyMultithreadClass myMultithread = new MyMultithreadClass() ; //создаем екземпляр нашего класса

    thread1.setPriority (1) ; //можно задавать приоритет от 0 до 10

    thread2.setPriority (9) ; //теперь результат будет более предсказуем

    thread3.setPriority (5) ;

    thread1.start () ;

    thread2.start () ;

    thread3.start () ;

Теперь предлагаю посмотреть на второй метод создания многопоточности: унаследование от класса. Полагаю, Вы помните из статьи , что унаследоваться в Java можно только от одного класса. В этом и недостаток такого метода. Ваш класс уже не сможет унаследовать другие классы:

    package com.java ;

    public class MyMultithreadClass extends Thread { //создаем наш многопоточный класс унаследуя его от Thread

    public static int i = 0 ; //изменили переменную на static, чтобы она не была привязана к классу.

    public void run() { //делаем реализацию метода run

    // TODO Auto-generated method stub

    MyMultithreadClass thread1 = new MyMultithreadClass() ;

    MyMultithreadClass thread2 = new MyMultithreadClass() ;

    MyMultithreadClass thread3 = new MyMultithreadClass() ;

    thread1.start () ;

    thread2.start () ;

    thread3.start () ;

Результат выполнения все еще не предсказуем:

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

Потоки имеют определенные состояния. Всего их 4:

  • создание (когда мы написали new Thread();
  • старт (thread1.start());
  • выполнение (пока выполняется метод run());
  • завершение (когда поток выполнил свою работу).

Вот Вам полезная картинка:

Как видим на рисунке, поток может еще и ожидать. Для того, чтобы на время заставить поток прекратить свою работу в классе есть метод wait() , который приостанавливает выполнение пока не будет вызван метод notify() . Неправильно говорить, что это методы класса потока. Это методы объекта. Может у Вас когда то будет вопрос на тесте или собеседовании назвать методы класса Object; тогда к тем методам что Вы вспомните можете смело называть wait() и notify().

Из статических методов есть метод sleep() , который принимает целочисленную переменную в качестве миллисекунд на который следует приостановить поток. Вызов этого метода можно осуществлять в любом месте кода, где Вы желаете приостановить или замедлить выполнение. Я часто использовал этот метод в циклах, когда нужно было в консоли увидеть большое количество данных и найти нужное. Да, поначалу, я дебажил в консоли)).

Таким образом переменная будет выводиться с задержкой в 500 миллисекунд. Не забывайте только, что данный метод может выбрасывать InterruptedException поэтому, при его вызове нужно или оборачивать его в блок try-catch или прописать throws InterruptedException после названия метода.

Есть еще метод yield(), при вызове которого, поток на время прекращает работу, позволяя другим потокам тоже выполниться.

Чтобы уничтожить потоки есть методы stop() и destroy() . Разница между ними в том, что при вызове destroy() поток уже нельзя возобновить. Можно прервать выполнение потока вызвав метод interrupt() .

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