- Потоки. Класс Thread и интерфейс Runnable
- Создание собственного потока
- Создание потока с интерфейсом Runnable
- Ключевое слово syncronized — синхронизированные методы
- Looper
- Create thread in loop java
- Simple Java Thread Example: Creating and Starting Threads
- CrunchifyThreads.java
- Console output:
- Suggested Articles.
Потоки. Класс Thread и интерфейс Runnable
В русской терминологии за термином Thread укрепился перевод «Поток». Хотя это слово также можно перевести как «Нить». Иногда в зарубежных учебных материалах понятие потока объясняется именно на нитях. Продолжим логический ряд — там где нити, там и клубок. А где клубок, там и кот. Сразу видно, что у переводчиков не было котов. Так и возникла путаница. Тем более что существуют другие потоки под термином Stream. Переводчики, вообще странный народ.
Когда запускается любое приложение, то начинает выполняться поток, называемый главным потоком (main). От него порождаются дочерние потоки. Главный поток, как правило, является последним потоком, завершающим выполнение программы.
Несмотря на то, что главный поток создаётся автоматически, им можно управлять через объект класса Thread. Для этого нужно вызвать метод currentThread(), после чего можно управлять потоком.
Класс Thread содержит несколько методов для управления потоками.
- getName() — получить имя потока
- getPriority() — получить приоритет потока
- isAlive() — определить, выполняется ли поток
- join() — ожидать завершение потока
- run() — запуск потока. В нём пишите свой код
- sleep() — приостановить поток на заданное время
- start() — запустить поток
Получим информацию о главном потоке и поменяем его имя.
Thread mainThread = Thread.currentThread(); mInfoTextView.setText("Текущий поток: " + mainThread.getName()); // Меняем имя и выводим в текстовом поле mainThread.setName("CatThread"); mInfoTextView.append("\nНовое имя потока: " + mainThread.getName());
Имя у главного потока по умолчанию main, которое мы заменили на CatThread.
Вызовем информацию о названии потока без указания метода.
Thread mainThread = Thread.currentThread(); mInfoTextView.setText("Текущий поток: " + mainThread);
В этом случае можно увидеть строчку Thread[main,5,main] — имя потока, его приоритет и имя его группы.
Создание собственного потока
Создать собственный поток не сложно. Достаточно наследоваться от класса Thread.
Объявим внутри нашего класса внутренний класс и вызовем его по щелчку, вызвав метод start().
public class MyThread extends Thread < public void run() < Log.d(TAG, "Mой поток запущен. "); >> public void onClick(View view)
Как вариант, перенести вызов метода start() в конструктор.
public void onClick(View view) < MyThread myThread = new MyThread(); >public class MyThread extends Thread < // Конструктор MyThread() < // Создаём новый поток super("Второй поток"); Log.i(TAG, "Создан второй поток " + this); start(); // Запускаем поток >public void run() < Log.d(TAG, "Mой поток запущен. "); try < for (int i = 5; i >0; i--) < Log.i(TAG, "Второй поток: " + i); Thread.sleep(500); >> catch (InterruptedException e) < Log.i(TAG, "Второй поток прерван"); >> >
Создание потока с интерфейсом Runnable
Есть более сложный вариант создания потока. Для создания нового потока нужно реализовать интерфейс Runnable. Вы можете создать поток из любого объекта, реализующего интерфейс Runnable и объявить метод run().
Внутри метода run() вы размещаете код для нового потока. Этот поток завершится, когда метод вернёт управление.
Когда вы объявите новый класс с интерфейсом Runnable, вам нужно использовать конструктор:
Thread(Runnable объект_потока, String имя_потока)
В первом параметре указывается экземпляр класса, реализующего интерфейс. Он определяет, где начнётся выполнение потока. Во втором параметре передаётся имя потока.
После создания нового потока, его нужно запустить с помощью метода start(), который, по сути, выполняет вызов метода run().
Создадим новый поток внутри учебного проекта в виде вложенного класса и запустим его.
package ru.alexanderklimov.expresscourse; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import static ru.alexanderklimov.expresscourse.R.id.textViewInfo; public class MainActivity extends AppCompatActivity < final String TAG = "ExpressCourse"; private Button mButton; private EditText mResultEditText; private TextView mInfoTextView; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = findViewById(R.id.buttonGetResult); mResultEditText = findViewById(R.id.editText); mInfoTextView = findViewById(textViewInfo); >public void onClick(View view) < new MyRunnable(); // создаём новый поток try < for (int i = 5; i >0; i--) < Log.i(TAG, "Главный поток: " + i); Thread.sleep(1000); >> catch (InterruptedException e) < Log.i(TAG, "Главный поток прерван"); >> class MyRunnable implements Runnable < Thread thread; // Конструктор MyRunnable() < // Создаём новый второй поток thread = new Thread(this, "Поток для примера"); Log.i(TAG, "Создан второй поток " + thread); thread.start(); // Запускаем поток >// Обязательный метод для интерфейса Runnable public void run() < try < for (int i = 5; i >0; i--) < Log.i(TAG, "Второй поток: " + i); Thread.sleep(500); >> catch (InterruptedException e) < Log.i(TAG, "Второй поток прерван"); >> > >
Внутри конструктора MyRunnable() мы создаём новый объект класса Thread
thread = new Thread(this, "Поток для примера");
В первом параметре использовался объект this, что означает желание вызвать метод run() этого объекта. Далее вызывается метод start(), в результате чего запускается выполнение потока, начиная с метода run(). В свою очередь метод запускает цикл для нашего потока. После вызова метода start(), конструктор MyRunnable() возвращает управление приложению. Когда главный поток продолжает свою работу, он входит в свой цикл. После этого оба потока выполняются параллельно.
Можно запускать несколько потоков, а не только второй поток в дополнение к первому. Это может привести к проблемам, когда два потока пытаюсь работать с одной переменной одновременно.
Ключевое слово syncronized — синхронизированные методы
Для решения проблемы с потоками, которые могут внести путаницу, используется синхронизация.
Метод может иметь модификатор syncronized. Когда поток находится внутри синхронизированного метода, все другие потоки, которые пытаются вызвать его в том же экземпляре, должны ожидать. Это позволяет исключить путаницу, когда несколько потоков пытаются вызвать метод.
syncronized void meow(String msg);
Кроме того, ключевое слово syncronized можно использовать в качестве оператора. Вы можете заключить в блок syncronized вызовы методов какого-нибудь класса:
Looper
Поток имеет в своём составе сущности Looper, Handler, MessageQueue.
Каждый поток имеет один уникальный Looper и может иметь много Handler.
Считайте Looper вспомогательным объектом потока, который управляет им. Он обрабатывает входящие сообщения, а также даёт указание потоку завершиться в нужный момент.
Поток получает свой Looper и MessageQueue через метод Looper.prepare() после запуска. Looper.prepare() идентифицирует вызывающий потк, создаёт Looper и MessageQueue и связывает поток с ними в хранилище ThreadLocal. Метод Looper.loop() следует вызывать для запуска Looper. Завершить его работу можно через метод looper.quit().
class LooperThread extends Thread < public Handler mHandler; public void run() < Looper.prepare(); mHandler = new Handler() < public void handleMessage(Message msg) < // process incoming messages here >>; Looper.loop(); > >
Используйте статический метод getMainLooper() для доступа к Looper главного потока:
Looper mainLooper = Looper.getMainLooper();
Создадим два потока. Один запустим в основном потоке, а второй отдельно от основного. Нам будет достаточно двух кнопок и метки.
Обратите внимание, как запускаются потоки. Первый поток запускается с помощью метода start(), а второй — run(). Затем проверяем, в каком потоке мы находимся.
package ru.alexanderklimov.as23; import android.os.Bundle; import android.os.Looper; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity < TextView mInfoTextView; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startButton = (Button) findViewById(R.id.button_start); Button runButton = (Button) findViewById(R.id.button_run); mInfoTextView = (TextView) findViewById(R.id.textview_info); startButton.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < Thread thread = new Thread(new MyRunnable()); thread.start(); //в фоновом потоке >>); runButton.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View view) < Thread thread = new Thread(new MyRunnable()); thread.run(); //в текущем потоке >>); > private class MyRunnable implements Runnable < @Override public void run() < // Проверяем, в каком потоке находимся if (Looper.getMainLooper().getThread() == Thread.currentThread()) < mInfoTextView.setText("В основном потоке"); >else < runOnUiThread(new Runnable() < @Override public void run() < mInfoTextView.setText("В фоновом потоке"); >>); > > > >
Эта тема достаточно сложная и для большинства не представляет интереса и необходимости изучать.
В Android потоки в чистом виде используются всё реже и реже, у системы есть собственные способы.
Create thread in loop java
- Introduction to Java
- The complete History of Java Programming Language
- C++ vs Java vs Python
- How to Download and Install Java for 64 bit machine?
- Setting up the environment in Java
- How to Download and Install Eclipse on Windows?
- JDK in Java
- How JVM Works – JVM Architecture?
- Differences between JDK, JRE and JVM
- Just In Time Compiler
- Difference between JIT and JVM in Java
- Difference between Byte Code and Machine Code
- How is Java platform independent?
- Decision Making in Java (if, if-else, switch, break, continue, jump)
- Java if statement with Examples
- Java if-else
- Java if-else-if ladder with Examples
- Loops in Java
- For Loop in Java
- Java while loop with Examples
- Java do-while loop with Examples
- For-each loop in Java
- Continue Statement in Java
- Break statement in Java
- Usage of Break keyword in Java
- return keyword in Java
- Object Oriented Programming (OOPs) Concept in Java
- Why Java is not a purely Object-Oriented Language?
- Classes and Objects in Java
- Naming Conventions in Java
- Java Methods
- Access Modifiers in Java
- Java Constructors
- Four Main Object Oriented Programming Concepts of Java
- Inheritance in Java
- Abstraction in Java
- Encapsulation in Java
- Polymorphism in Java
- Interfaces in Java
- ‘this’ reference in Java
Simple Java Thread Example: Creating and Starting Threads
A thread — sometimes known as an execution context or a lightweight process–is a single sequential flow of control within a process. As a sequential flow of control, a thread must carve out some of its own resources within a running program (it must have its own execution stack and program counter for example).
The code running within the thread only works within that context. Thus, other texts use execution context as a synonym for thread.
Let’s understand and introduction to Java threads. Below Java Code will create and start 3 independent threads.
CrunchifyThreads.java
package crunchify.java.tutorials; /** * @author Crunchify.com * Simple Java Thread Example: Creating and Starting Threads */ public class CrunchifyThreads < public static void main(String args[]) < new crunchifyThreadTest("Facebook").start(); new crunchifyThreadTest("Twitter").start(); new crunchifyThreadTest("Google").start(); >> class crunchifyThreadTest extends Thread < public crunchifyThreadTest(String crunchifyString) < // super: Allocates a new Thread object. // This constructor has the same effect as Thread (null, null, name). super(crunchifyString); >public void run() < for (int counter = 1; counter catch (InterruptedException e) < // printStackTrace(): Prints this throwable and its backtrace to the standard error stream. // This method prints a stack trace for this Throwable object on the error output stream that is the value of the field System.err. e.printStackTrace(); >> System.out.println("\n========= Test Finished for: " + getName() + "\n"); > >
The run() method is the heart of any Thread–it’s where the action of the Thread takes place.
The run() method of the ThreadTest class contains a for loop that iterates 5 times. In each iteration the method displays the iteration number and the name of the Thread than sleeps for a random interval between 0 and 2 seconds.
After the loop has finished, the run() method prints “Test Finished For: ” along with the name of the thread.
Console output:
Just run above program as a Java Application and you should see result similar to this one.
Loop 1: Twitter, ID: 15, State: RUNNABLE Loop 1: Google, ID: 16, State: RUNNABLE Loop 1: Facebook, ID: 14, State: RUNNABLE Loop 2: Facebook, ID: 14, State: RUNNABLE Loop 2: Google, ID: 16, State: RUNNABLE Loop 2: Twitter, ID: 15, State: RUNNABLE Loop 3: Twitter, ID: 15, State: RUNNABLE Loop 4: Twitter, ID: 15, State: RUNNABLE Loop 3: Facebook, ID: 14, State: RUNNABLE Loop 5: Twitter, ID: 15, State: RUNNABLE Loop 3: Google, ID: 16, State: RUNNABLE ========= Test Finished for: Twitter Loop 4: Facebook, ID: 14, State: RUNNABLE Loop 4: Google, ID: 16, State: RUNNABLE Loop 5: Google, ID: 16, State: RUNNABLE ========= Test Finished for: Google Loop 5: Facebook, ID: 14, State: RUNNABLE ========= Test Finished for: Facebook Process finished with exit code 0
Hope this helps you understand threading concept in Java.
If you liked this article, then please share it on social media. Have a question or suggestion? Please leave a comment to start the discussion.