2016-01-15 4 views
1

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€"]]

другой поток (оранжевый) должен бежать полностью без изменений всем этим. Так что все разные фрукты должны бегать одновременно, но элементы с одинаковыми фруктами должны каким-то образом уважать друг друга. Существует ли тип синхронизации, который только блокирует экземпляры с одинаковыми именами фруктов, но не блокирует какие-либо другие экземпляры?


Я много читал о синхронизации, замках и т. Д., Но не могу найти решение для своей проблемы.
Было бы хорошо, если кто-то может мне помочь, спасибо заранее!

+0

_... и запускает поток для каждого слова в table._ Это звучит как плохая идея. Лучшей идеей было бы отправить _task_ в «ExecutorService» для каждого слова в таблице.Настройте ExecutorService с соответствующим количеством потоков для вычислительной и пропускной способности ввода-вывода машины, на которой вы работаете. –

+0

Как вы можете видеть в моем «основном» классе, я уже использовал ExecutorService. Возможно, его формулировка путается, но «начинает поток» означает «отправляет задачу в ExecutorService для обработки в потоке». Я использую FixedThreadPool из 20, потому что больше связей блокируется на веб-сайте. – MasterReY

ответ

0

XY проблема. Синхронизация не исправит это. Даже если предположить, что вы можете реализовать его, второй поток будет просто заблокирован первым, а затем приступить к нежелательному обходу.

Вы можете добавить набор слов, которые начали обрабатываться, или добавить фиктивный элемент в карту, которая показывает, что она уже обрабатывается, хотя и не завершена.

0

Если вы получаете полный список слов сначала, тогда просто предварительно заполните карту с помощью значений placeholder. то вам нужно всего лишь запустить потоки для каждого из ключей на вашей карте.

+0

Да, сначала разобрать таблицу слов. Однако только начальные потоки для каждого ключа карты не работают, потому что большинство слов существует несколько раз на карте и каждый раз, когда у них разные данные в другом столбце, которые мне нужно добавить к объекту в значении каждого ключа. – MasterReY

+0

@MasterReY - это не имеет смысла, если вы используете имя фрукта в качестве ключа к таблице, вы можете иметь только один фрукт за имя. – jtahlborn

+0

Да, но в таблице можно сказать, что у меня есть слово «яблоко» несколько раз. Каждый раз, когда он имеет разные данные в определенном столбце в одной строке. (1,20 €, 1,50 €, 2,30 €, ....) Как и в Питере, продал яблоко за 1,20 €, Лиза продала яблоко за 1,50 € и т. Д. Таким образом, цель состоит в том, чтобы слово «яблоко» в качестве ключа на карте и один объект из яблока, содержащий основную информацию о яблоках с сайта и все разные данные (1,20 €, 1,50 € и т. д.). У этого фруктового объекта есть список. – MasterReY

0

Не уверен, что мой ответ соответствует тому, как вы структурировали свое приложение, но следует, что это «правильный» способ обработки вашего типа проблем, который довольно распространен в параллельных приложениях.

Это, безусловно, возможно получить то, что вы хотите, и избежать «двойных» вычислений. Я предлагаю вам прочитать java параллелизм на практике и, более конкретно, глава 5 Я думаю, что это так, где они должны делать memoization вычислений (огромные вычисления), а также избегать двух потоков, вычисляющих одинаковое число.

Некоторые трюки, которые вы можете применить, - использовать putIfAbsent (метод только поместить элемент на карту, если он еще не существует). Более того, я предлагаю вам хранить Futures на вашей карте. https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html Они представляют собой результат вычисления, и тогда вы оба проведете вычисления и убедитесь, что он не будет вычисляться дважды, но вы все равно получите результат для обоих потоков, поскольку вы просто вызываете future.get(), который блокирует пока не будет получен результат. Я не буду вдаваться в подробности, поскольку на самом деле это очень хорошо показано в java-параллельной книге.

Так что-то вроде (псевдокод)

if !map.containsKey(word) { 
    Future f = new Future(word) 
    map.putIfAbsent(word, future<curWord>) 
    f.get() 
} else { 
    Future f = map.get(word) 
    f.get() 
} 
+0

Первый абзац не ясен. О чем вы это говорите? Предложение пользователя? Что следует в вашем ответе? – EJP

+0

Что следует в ответе. Я исправил, так что, надеюсь, теперь это должно быть яснее. – PNS

+0

«Это« правильный »способ обработки вашего типа проблем», по-прежнему читается, как будто вы одобряете предложение OP в первом абзаце. Я предлагаю вам вместо этого использовать что-то вроде «как следует». – EJP

Смежные вопросы