EDIT: Я добавил пример таблицы (см. Ссылку на страницы google) и как должен выглядеть результирующий объект Apple.Как заблокировать блок кода на основе определенного условия?
Я запрограммировал многопоточный веб-скребок с помощью Jsoup, который извлекает информацию с веб-сайта и сохраняет ее на карте. Главное, с чем я не могу работать, это то, что программа НЕ подключается к веб-сайту, если она уже очистила определенную информацию.
Информация о программе
извлекает информацию из таблицы на сайте и запускает поток для каждого слова в таблице.
Итак, потоки начинаются с определенного слова как члена класса. Каждый поток также имеет тот же объект ConcurrentHashMap. Мой план состоял в том, чтобы проверить, существует ли слово на карте в качестве ключа.
Если нет, он должен подключиться к веб-сайту, чтобы получить информацию о слове, добавить к нему некоторые данные и затем поместить его на карту.
Если на карте уже содержится слово, поток должен получить значение с карты и только добавить к нему данные.
Таким образом, главная цель - не подключаться к веб-сайту дважды для одного и того же слова.
Вот соответствующие фрагменты кода:
Основной класс
Начиная нить для каждого слова в таблице. «element» содержит слово и url для получения дополнительной информации о слове.
for (Element element : allRelevantTableElements) {
executorService.execute(new Worker(element, data, concurrentMap));
}
Рабочий класс
1. Проверьте, если слово уже на карте.
2a. Если он находится на карте, просто добавьте в него данные.
2b. Если это не карта, очистите информацию с веб-сайта, а затем добавьте в нее данные.
public class Worker implements Runnable {
MyWebScraper scraper;
Element element;
String data;
ConcurrentMap<String, Fruit> concurrentMap;
public Worker(Element element, String data, ConcurrentMap<String, Fruit> concurrentMap) {
this.element = element;
this.data = data;
this.concurrentMap = concurrentMap;
}
@Override
public void run() {
Fruit fruit;
if (concurrentMap.containsKey(element.text())) {
fruit = concurrentMap.get(element.text());
fruit.addData(data)
} else {
scraper = new WebScraper("http://fruitinformation.com" + element.attr("href"));
scraper.connect();
fruit = scraper.getInformation();
fruit.addData(data)
}
concurrentMap.put(element.text(), fruit);
}
}
Пример
Допустим, таблица выглядит следующим образом:
https://docs.google.com/spreadsheets/d/1JF8sh8Sp9y0SV3Xb5mlISgcJp5s_DhaSp3KbnQLa248/edit?usp=sharing
Основной класс начнется 3 темы:
темы 1: Элемент содержит "Яблоко" и в suburl "/ apple",
Данные содержат "1,20 €"
Тема 2: Элемент содержит "Оранжевый" и suburl "/ оранжевый",
данных содержит "2,40 €"
Тема 3: Элемент содержит "Яблоко" и suburl "/ яблоко",
данных содержит "1,50 €"
Проблема что все потоки выполняются почти одновременно, поэтому нитки 1 и 3 будут проверять, находится ли «яблоко» уже на карте, и BOTH получит false как результат. Поэтому они ОБА объединяются на сайт fruitinformation.com/apple и получают основную информацию о яблоках, которые мне нужны только один раз.Затем BOTH добавит свои данные к возвращенному объекту и поместит его в карту, но поток 1 сделает это сначала с «1,20 €», а затем поток 2 переопределит яблоко «1,20 €» с его «1,50» € apple в качестве значения.
Однако цель состоит в том, что только один поток яблока подключается к веб-сайту и добавляет его данные (например, 1,20 €), а затем другой понимает, что на карте уже существует объект apple и только добавляет свои данные (1,50 евро) к существующему яблоке плодовые объекты имеют списки для этого
Таким образом, в результате чего запись карта должна выглядеть следующим образом:..
Key=Apple , Value= Fruit["Apple", basicInformationFromWebsite, List["1,20€"; "1,50€"]]
другой поток (оранжевый) должен бежать полностью без изменений всем этим. Так что все разные фрукты должны бегать одновременно, но элементы с одинаковыми фруктами должны каким-то образом уважать друг друга. Существует ли тип синхронизации, который только блокирует экземпляры с одинаковыми именами фруктов, но не блокирует какие-либо другие экземпляры?
Я много читал о синхронизации, замках и т. Д., Но не могу найти решение для своей проблемы.
Было бы хорошо, если кто-то может мне помочь, спасибо заранее!
_... и запускает поток для каждого слова в table._ Это звучит как плохая идея. Лучшей идеей было бы отправить _task_ в «ExecutorService» для каждого слова в таблице.Настройте ExecutorService с соответствующим количеством потоков для вычислительной и пропускной способности ввода-вывода машины, на которой вы работаете. –
Как вы можете видеть в моем «основном» классе, я уже использовал ExecutorService. Возможно, его формулировка путается, но «начинает поток» означает «отправляет задачу в ExecutorService для обработки в потоке». Я использую FixedThreadPool из 20, потому что больше связей блокируется на веб-сайте. – MasterReY