-
Notifications
You must be signed in to change notification settings - Fork 3
Java Concurrency
Многопоточность. Ясно, что делать два дела одновременно и хорошо - это несомненный плюс. Вы можете ехать в метро и слушать музыку, чистить зубы и смотреть фильм. Мы живем в многопоточном мире:)
Зачем в Java?
- Используем CPU, несколько ядер
- многозадачность и производительность
- асинхронная обработка событий
В чем же разница между процессом и потоком?
- Процессы обладают собственным адресным пространством.
- Потоки работают с общей памятью.
- С потоками работает именно планировщик ОС.
Создать поток просто - мы должны отнаследоваться от Thread
:
public class MyThread extends Thread {
@Override
public void run() {/*some work*/}
}
Запуск будет выглядеть как
MyThread thread = new MyThread();
thread.start();
При этом, надо обязательно помнить, что вызывать надо именно start
, который уже в отдельном потоке запустит то, что вы написали в run
.
И да, мы можем переопределить start - но этого делать не стоит, так как там своя логика запуска вашего потока.
Внимательный читатель сразу спросит, как так, а если я хочу, чтобы мой класс был потоком, но он уже наследует какой-то другой класс. Как быть?
Тут поможет второй вариант создания потока. Это разумеется реализация интерфейса! Наш интерфейс называется Runnable
.
class Task implements Runnable {
@Override
public void run() {/*some work*/}
}
Запуск:
Thread thread = new Thread(new Task());
thread.start();
Тут все просто - мы реализуем интерфейс Runnable
и объект такого класса передаем в конструктор Thread
.
В принципе мы могли бы создать даже анонимный класс прямо в создании Thread
.
Т.е выглядело бы это как-то так:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {/*some work*/}
});
thread.start();
Есть еще третий вариант: это создать Timer
.
Timer timer = new Timer();
timer.schedule(new TimeTask {
@Override
public void run() {/*some work*/}
}, 60);
Выполнение задачи в отдельном потоке, но по таймеру.
Теперь посмотрим что будет, если я вместо start() буду вызывать именно run() метод.
void wrongRun() {
ThreadExample te1 = new ThreadExample("My thread", 1);
ThreadExample te2 = new ThreadExample("My thread 2", 2);
te1.run();
te2.run();
}
И увидим мы то, что все будет выполняться последовательно, без многопоточности. Сначала отработает te1, а уже после него начнет работу te2. Поэтому НЕ вызывайте run() напрямую - это бесполезно.