В этой статье имитируются примеры производитель-потребитель с помощью wait(), notify(), notifyAll() и объясняется, почему при использовании notify() возникает взаимоблокировка.
1. Пример кода
1.1 Производители
package com.example.hxk.thread.demo;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author Smith 2019/3/21
*/
public class Producer implements Runnable{
List<Integer> cache;
public void put() throws InterruptedException {
synchronized (cache) {
while (cache.size() == 1) {
try {
cache.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
TimeUnit.SECONDS.sleep(1);
cache.add(1);
System.out.println(Thread.currentThread().getName() + "生产者生产了一条。");
cache.notify();
}
}
public Producer(List<Integer> cache) {
this.cache = cache;
}
@Override
public void run() {
while (true) {
try {
put();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1.2 Потребители
package com.example.hxk.thread.demo;
import java.util.List;
/**
* @author Smith 2019/3/21
*/
public class Customer implements Runnable {
List<Integer> cache;
public Customer(List<Integer> cache) {
this.cache = cache;
}
private void custom() {
synchronized (cache) {
while (cache.size() == 0) {
try {
cache.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cache.remove(0);
System.out.println(Thread.currentThread().getName() + "消费者消费了一条。");
cache.notify();
}
}
@Override
public void run() {
while (true) {
custom();
}
}
}
1.3 Тестовый код
1.3.1 Один производитель и один потребитель
package com.example.hxk.thread.demo;
import java.util.ArrayList;
import java.util.List;
/**
* @author Smith 2019/3/21
*/
public class Test {
public static void main(String[] args) {
List<Integer> cache = new ArrayList<>();
new Thread(new Producer(cache), "P1").start();
new Thread(new Customer(cache), "C1").start();
}
}
результат операции:
в заключении:
С уведомлением, одним производителем и одним потребителем производство и потребление работают без проблем.
1.3.2 Один производитель и два потребителя
package com.example.hxk.thread.demo;
import java.util.ArrayList;
import java.util.List;
/**
* @author Smith 2019/3/21
*/
public class Test {
public static void main(String[] args) {
List<Integer> cache = new ArrayList<>();
new Thread(new Producer(cache), "P1").start();
new Thread(new Customer(cache), "C1").start();
new Thread(new Customer(cache), "C2").start();
}
}
результат операции:
в заключении:
В случае использования уведомления и одного производителя и двух потребителей программа блокируется после двух производств.
1.3.3 Producer и Customer в notify() заменены notifyAll()
Код больше не липкий.
результат операции
Программа снова работает в обычном режиме.
2. Разница между notify() и notifyAll
Каждый объект синхронизации имеет собственный пул блокировок и пул ожидания.
2.1 Пул блокировки и пул ожидания
- Пул блокировки: предположим, что поток A уже владеет блокировкой объекта (примечание: не класса), а другие потоки хотят вызвать синхронизированный метод (или синхронизированный блок) этого объекта, потому что эти потоки входят в синхронизированный метод объекта. Владение блокировкой объекта должно быть получено заранее, но блокировка объекта в настоящее время принадлежит потоку A, поэтому эти потоки входят в пул блокировок объекта.
- Пул ожидания: Предположим, что поток А вызывает метод ожидания () объекта, поток А снимает блокировку объекта (поскольку метод ожидания () должен появиться в синхронизированном, поэтому естественном при выполнении методе ожидания () до того, как поток А у него уже есть блокировка объекта), в то время как поток a входит в объект пула ожидания. Если другой поток вызывает тот же метод объекта notifyAll(), весь пул потоков, ожидающий блокировки объекта, войдет в пул объекта, готовый конкурировать за право владения блокировкой. Если другой поток вызывает тот же метод уведомления объекта (), то только один поток в пуле ожидания объекта (случайный) войдет в пул блокировки объекта.
2.2 Разница между notify() и notifyAll()
- Когда поток вызывает метод wait(), он снимет блокировку и войдет в пул ожидания и не будет участвовать в соревновании за блокировку.
- После вызова notify() поток из ожидающего пула (будет только один поток) войдет в пул блокировок объекта для участия в конкурсе блокировок.Если конкурс будет успешным, блокировка будет получена.Если конкурс не пройден , он останется в пуле блокировок и будет ждать следующего конфликта блокировок A.
- После вызова notifyAll() все потоки в пуле ожидания войдут в пул блокировок объекта для участия в соревновании блокировок.
3. Пример анализа
Знание знания 2, вышеприведенные три примера легко объяснить.
1.3.1: Потому что есть только один продюсер и потребитель, всегда есть только один нить в ожидающем пуле, либо продюсер просыпается, что потребитель просыпается, или потребитель просыпается до продюсера, поэтому программа может работать успешно;
1.3.2: привести возможный пример
- Теперь есть три потока: производитель P1, потребитель C1 и C2. Когда они начинают работать, все три ждут конкуренции в пуле блокировок. Предположим, что C1 захватывает блокировку. Когда C1 выполняется, нет ресурсов для потребления и вызова ожидания () , снимите блокировку и войдите в пул ожидания.
- C2 захватывает блокировку и начинает потреблять Аналогично C2 также входит в пул ожидания. Теперь в пуле блокировок остался только P1.
- P1 получает блокировку и запускает производство.После завершения производства P1 начинает вызывать метод notify() для пробуждения C1 или C2 в пуле ожидания, а затем P1 вызывает метод wait() для снятия блокировки и входит в бассейн ожидания.
- Предполагая, что C1 пробужден, C1 входит в пул блокировок и получает блокировку.После потребления метод notify() пробуждает C2, C2 входит в пул блокировок, а C1 входит в пул ожидания.Теперь в пуле блокировок есть только C1 .
- C1 получил замок и обнаружил, что не было ресурсов для потребления. После ожидания () блокировка была выпущена, и он ввел в пул ожидания. Теперь все три потока ждут в пуле, и в бассейне блокировки нет нитей. привести к тупике!
1.3.3: После notifyAll() не возникает ситуации, когда пробуждаются только похожие потоки, поэтому в 1.3.2 не будет взаимоблокировок.
Цитировать
- Автор: отправлено по электронной почте
Источник: ЦСДН оригинал:blog.csdn.net/emaied/art...
- Автор: Пафф Райдер
Источник: Цзяньшу оригинал:woo woo Краткое описание.com/fear/45626 4 oh 0…