Эта статья призвана рассказать самые скучные основы самым распространенным языком.
Полная схема текста:
1. Что такое нить? (начальство)
2. Разница и связь между потоками и процессами (Часть 1)
3. Способ создания многопоточности (Часть 1)
4. Жизненный цикл потока (включен)
5. Контроль потока (вкл.)
6. Синхронизация потоков (ниже)
7. Пул потоков (ниже)
8. Базовое использование ThreadLocal (ниже)
9. Безопасность потоков (часть 2)
1. Что такое нить
Поток — это поток выполнения в процессе, и это базовая единица, независимо запланированная и управляемая системой.
Что такое нити? Что это за процесс?
Это может немного сбить с толку, позвольте мне дать вам каштан:
Завод А — это завод по производству автомобилей, сегодня сотрудник Чжан Сан собирается доставить товар, а сотрудник Ли Си собирается запастись. здесь
- Завод — это процесс (конечно, заброшенный завод без признаков жизни не может считаться процессом)
- Сотрудник Чжан Сан идет доставить это нить
- Сотрудник Ли Си пошел закупать товар, что тоже нить
Как видно из примера
Под процессом понимается запущенная программа (программа, которая не запущена, система не будет выделять для нее ресурсы).Каждый процесс имеет свое независимое пространство памяти.Когда программа входит в память для запуска, программа может содержать несколько программ. Поток выполнения, этот поток выполнения программы является потоком.
Почти все операционные системы поддерживают многопоточный параллелизм.Как и компьютеры, которые мы обычно используем для работы, мы можем использовать для открытия eclipse для написания кода, для открытия NetEase Cloud Music для прослушивания класса, а также для открытия Youdao Translation, всегда готового к работе. перевести наш китайский на английский…
Видно, что наш компьютер может поддерживать выполнение нескольких приложений одновременно, но на самом деле для каждого ЦП он может выполнять только одну программу в момент времени, то есть один процесс, так зачем же мы его открываем одновременно Можно ли запускать несколько программ?
Это потому, что современные компьютеры имеют более одного процессора. Конечно это причина.
Самое главное, что во время работы программы ЦП переключает выполнение туда и обратно между разными программами с высокой скоростью, поэтому так называемое «параллельное выполнение» на самом деле является не выполнением нескольких программ одновременно, а выполнение программы системой Планирование таким образом, чтобы казалось, что она выполняется одновременно.
Итак, параллелизм в потоках:
Это означает, что ЦП выполняет несколько процессов в быстрой ротации, а не одновременно.
2. Разница между потоком и процессом
Через приведенное выше описание принципа мы уже можем видеть разницу, есть два основных момента
- Поток — это основная единица планирования и распределения, а процесс — основная единица, владеющая ресурсами.
- Поток — это поток выполнения в процессе, а процесс может содержать несколько потоков.
3. Создание нескольких потоков
1. Унаследуйте класс Thread, чтобы создать поток:
1public class ThreadTest extends Thread {
2 @Override
3 public void run() {
4 // 业务逻辑
5 super.run();
6 }
7
8 public static void main(String[] args) {
9 new ThreadTest().run();
10 new ThreadTest().run();
11 }
12}
2. Реализуйте интерфейс Runnable
1public class ThreadTest implements Runnable {
2 @Override
3 public void run() {
4 //业务逻辑
5 }
6
7 public static void main(String[] args) {
8 new ThreadTest().run();
9 new ThreadTest().run();
10 }
11}
3. Создавайте с Callable и Future
Интерфейс Callable — это новый интерфейс после jdk5.Он предоставляет метод вызова в качестве тела выполнения потока, который похож на метод запуска потока, но его функция более мощная:
- он может иметь возвращаемое значение
- Он может объявить об исключении
Поэтому, как и в случае с Runnable, вы можете создать объект Callable в качестве цели потока и реализовать его метод вызова в качестве тела выполнения.
В то же время jdk5 предоставляет интерфейс Future для представления возвращаемого значения метода вызова в интерфейсе Callable и предоставляет класс реализации FutureTask для интерфейса Future, который реализует интерфейс Future и интерфейс Runable.Он имеет следующие методы. :
- boolean cancal(boolean mayInterruptRunning): попытка отменить вызываемую задачу, связанную с этим Future
- V get(): возвращает возвращаемое значение метода call() в задаче Callable.Вызов этого метода приведет к блокировке программы, и возвращаемое значение не будет получено, пока не завершится дочерний поток.
- V get(long timeout,TimeUnit unit):
- boolean isCancel(): возвращает true, если вызываемая задача была отменена до ее нормального завершения.
- boolean isDone(): возвращает true, если задача Callable завершена.
1public static void main(String[] args) {
2
3 //1)创建一个Callable实现类,并实现call方法
4 //2)用FutrueTask来包装类的实例
5 FutureTask ft=new FutureTask<>(new Callable<Integer>() {
6 @Override
7 public Integer call() throws Exception {
8 System.out.println("执行了");
9 try {
10 Thread.sleep(1000*5);
11 } catch (InterruptedException e1) {
12 // TODO Auto-generated catch block
13 e1.printStackTrace();
14 }
15
16 return 12;
17 }
18 });
19 //使用FutureTask对象作为target来创建并且启动线程
20 new Thread(ft).start();
21
22 //阻塞方式获取线程返回值
23 try {
24 System.out.println("返回值:"+ft.get());
25 } catch (InterruptedException e) {
26 // TODO Auto-generated catch block
27 e.printStackTrace();
28 } catch (ExecutionException e) {
29 // TODO Auto-generated catch block
30 e.printStackTrace();
31 }
32 //带有超时方式获取线程返回值
33 try {
34 System.out.println("返回值:"+ft.get(2,TimeUnit.SECONDS));
35 } catch (InterruptedException | ExecutionException | TimeoutException e) {
36 // TODO Auto-generated catch block
37 e.printStackTrace();
38 }
39
40 }
4. Жизненный цикл потока
После того, как поток создан, он не будет находиться в состоянии выполнения сразу.Согласно предыдущему определению параллелизма: даже если он запущен, он не будет находиться в состоянии выполнения навсегда.Если он всегда находится в состоянии выполнения, он всегда будут занимать ресурсы процессора, между ними нет возможности переключаться. Следовательно, поток имеет жизненный цикл, и его жизненный цикл включает в себя следующие состояния:
- Новый (НОВЫЙ)
- готовый (запускаемый)
- Бег
- Заблокировано
- мертв
1. Новое состояние
Когда поток создается с new в программе, он находится в новом состоянии.В это время он находится в том же состоянии инициализации, что и другие объекты в программе (выделение памяти, инициализация переменных-членов).
2. Состояние готовности
Когда программа вызывает метод запуска, программа находится в состоянии готовности, и jvm создаст для нее стек вызовов методов и счетчик программ.В это время состояние потока находится в состоянии выполнения, и оно не выполняется, но нуждается в планировании планировщика потоков, чтобы решить, что делать при запуске.
3. Рабочее состояние
Когда готовый поток получает ЦП, выполняется тело выполнения потока (метод выполнения), и поток находится в состоянии выполнения.
4. Состояние блокировки
Поток в рабочем состоянии, если время выполнения не очень, очень, очень короткое, будет прервано и перейдет в состояние блокировки из-за планирования ресурсов системой. Большинство операционных систем используют стратегию упреждающего планирования.После того, как поток получает ЦП, система дает потоку время для обработки задачи.Когда время истекает, система принудительно лишает поток ресурсов и выделяет их другим потокам. .Кто, это зависит от приоритета потока.
5. Состояние смерти
Поток в рабочем состоянии, когда он активно или пассивно завершается, поток находится в мертвом состоянии. Что касается формы торца, то обычно бывают следующие:
- Выполнение потока завершено, и поток завершается нормально
- Исключение или ошибка возникает во время выполнения потока и завершается пассивно.
- Поток активно вызывает метод остановки, чтобы завершить поток
5. Контроль потока
Java предоставляет некоторые методы потоков в их жизненном цикле, чтобы разработчики могли лучше контролировать потоки.
В основном это следующие методы:
- подожди: присоединяйся()
- Фон: setDeamon()
- Спать спать()
- доходность: доходность()
- Приоритет: setPriority()
1. Ожидание потока
Когда поток вызывает метод join() других потоков в потоке выполнения, вызывающий поток будет заблокирован до завершения потока join(), к которому присоединился метод join().
На первый взгляд, я не могу этого понять. Давайте напишем программу для проверки этого предложения:
1public class ThreadTest extends Thread {
2 @Override
3 public void run() {
4 System.out.println(getName()+"运行...");
5 for(int i=0;i<5;i++){
6 System.out.println(getName()+"执行:"+i);
7 }
8 }
9 public ThreadTest(String name){
10 super(name);
11 }
12 public static void main(String[] args) {
13 //main方法--主线程
14 //线程1
15 new ThreadTest("子线程1").start();
16 //线程2
17 ThreadTest t2=new ThreadTest("子线程2");
18 t2.start();
19
20 try {
21 t2.join(1000);
22 } catch (InterruptedException e) {
23 e.printStackTrace();
24 }
25 //线程3
26 new ThreadTest("子线程3").start();
27 }
28}
Смотрите вывод:
1子线程1运行...
2子线程2运行...
3子线程2执行:0
4子线程2执行:1
5子线程2执行:2
6子线程2执行:3
7子线程1执行:0
8子线程2执行:4
9子线程1执行:1
10子线程1执行:2
11子线程1执行:3
12子线程1执行:4
13子线程3运行...
14子线程3执行:0
15子线程3执行:1
16子线程3执行:2
17子线程3执行:3
18子线程3执行:4
Как видите, потоки 1 и 2 выполняются одновременно, а поток 3 не запускается, пока все они не закончат выполнение.
Отсюда видно, что:
После вызова метода join() последующие потоки должны дождаться завершения предыдущего выполнения перед выполнением, а не выполняться одновременно.
2. Нить переносится на задний план
Когда поток вызывает setDaemon(true), он превращается в фоновый поток для предоставления услуг для основного потока, а когда все потоки переднего плана умирают, фоновый поток также получает уведомление от JVM и автоматически умирает.
1ThreadTest t2=new ThreadTest("子线程2");
2//这是为后台线程,但必须在start前设置,因为前台线程死亡JVM会通知
3//后台线程死亡,但接受指令到响应需要时间。因此要自爱start前就设置
4 t2.setDaemon(true);
5 t2.start();
3. Нить сна
Когда работающему потоку необходимо приостановить выполнение и перейти в состояние блокировки, вызовите Thread.sleep.
4. Уступки потокам
Когда потоку в рабочем состоянии требуется приостановить выполнение и перейти в состояние готовности, вызовите
Thread.yield() может
5. Приоритет потока
Как упоминалось ранее, выполнение того или иного потока, которому система назначает ЦП, зависит от приоритета потока, поэтому каждый поток имеет определенный приоритет, а поток с более высоким приоритетом получит больше возможностей для выполнения.По умолчанию каждый поток имеет определенный приоритет.Приоритет потока по умолчанию такой же, как приоритет родительского потока, который его создал.
Когда нам нужен поток или больше возможностей для выполнения, вызовите
Thread.currentThread().setPriority(int newPriority);
метод, диапазон newPriority составляет 1 ~ 10.
Секреты многопоточности раскрыты здесь, в предыдущем эпизоде, а более продвинутое использование многопоточности будет рассмотрено в следующем эпизоде. Пожалуйста следуйте за мной.
Думаете, эта статья была вам полезна? пожалуйста, поделитесь с большим количеством людей
Обратите внимание на «Безграничное программирование» и улучшите свои навыки принуждения.