2012-01-30 2 views
2

У меня проблема с многопоточными в Java. Мне нужно сравнить большой список имен с самим собой (найти почти дубликаты).Темы в java не работают одновременно

Я разделил работу на 4 разных потока, каждый из которых сравнивал 1/4 списка с полным списком. Я использую тот же класс для всех 4 потоков.

Когда я смотрю на монитор потока, я вижу, что они не работают одновременно, они активны один за другим.

В чем проблема?

Это вводный метод моей резьбы класса:

@Override 
    public void run() { 
     try { 
      s = settings.conn.createStatement(); 
      JaroWinklerDistance jw = JaroWinklerDistance.JARO_WINKLER_DISTANCE; 

     for (int i = 0; i < names.size(); i++) { 
      for (int j = 0; j < allNames.size(); j++) { 
       if (j % 250 == 0) { 
       } 
       double proximity = jw.proximity(names.get(i), allNames.get(j)); 
       if (proximity > Double.parseDouble(settings.properties.getProperty("distanceTreshold")) && proximity < 1.00) { 
        if (names.get(i).length() > allNames.get(j).length()) { 
         substituteName(allNames.get(j), names.get(i)); 
         allNames.remove(allNames.get(j)); 
        } else { 
         substituteName(names.get(i), allNames.get(j)); 
         names.remove(names.get(i)); 
         break; 
        } 
       } 
      } 
     } 
    } catch (SQLException ex) { 
     Exceptions.printStackTrace(ex); 
    } 
} 

substituteName-метод выполняет SQL-запрос, который обновляет запись.

Нить создается следующим образом:

settings.getAllNames(); 
     int size = settings.allNames.size(); 
     int rest = size % 4; 
     int groupSize = (size-rest)/4; 

     GroupNormalizer a = new GroupNormalizer(settings.allNames, new ArrayList<String>(settings.allNames.subList(0, groupSize))); 
     GroupNormalizer b = new GroupNormalizer(settings.allNames, new ArrayList<String>(settings.allNames.subList(groupSize, (groupSize*2)))); 
     GroupNormalizer c = new GroupNormalizer(settings.allNames, new ArrayList<String>(settings.allNames.subList((groupSize * 2), (groupSize * 3)))); 
     GroupNormalizer d = new GroupNormalizer(settings.allNames, new ArrayList<String>(settings.allNames.subList((groupSize * 3), (groupSize*4 + rest)))); 
     a.start(); 
     b.start(); 
     c.start(); 
     d.start(); 

EDIT: все 4 нити чередовать много между работой и монитором (заблокированной) -Status

+0

Трудно сказать, не видя своего кода – hage

+0

Некоторый код был бы неплохо проанализировать, что может быть неправильно. –

+0

Я использую четырехъядерный ядро. Класс thread сравнивает часть большого списка.Если он находит почти дубликат, он обновляет записи базы данных соответственно. – Freek8

ответ

2

хмм это выглядит этой линии вызывает синхронизации зависанию:

if (proximity > Double.parseDouble(settings.properties.getProperty("distanceTreshold")) && proximity < 1.00) 

пытаются вытащить Double.parseDouble из петли, так как все там выглядит своего рода постоянной ко мне.

Кажется, что объект настроек блокирует доступ к общему доступу и таким образом замедляет вас.

Также похоже, что вы получаете доступ к БД во время вашей клаукуляции (ловя SQLEx), это замедлит вас очень большим фактором. Попробуйте отделить чтение и запись от процесса кластеризации.

+0

Я сделал то, что вы предлагали, и обнаружил, что несколько потоков обращались к файлу settings.properties. Я исправил это, и теперь он выглядит лучше. – Freek8

+0

Я также отделил вычисления от чтения/записи, и теперь они работают безупречно в одно и то же время (они всегда ждали доступа к базе данных) – Freek8

3

Executor Framework (пулами потоков) на помощь!

Пулы потоков управляют пулом рабочих потоков. Пулы потоков содержит рабочую очередь, в которой хранятся задачи, ожидающие выполнения.

+0

У меня было это раньше, но у меня такие же результаты. я сделал это ExecutorService es = Executors.newFixedThreadPool (4); es.submit (новая тема ..) – Freek8

+0

Уверен, что это не одноядерный целерон? – JMelnik

+1

Intel Core i7-2670QM @ 2.20GHz с памятью 8 ГБ – Freek8

0

Существует известная проблема с использованием Double.parseDouble в Java из нескольких потоков одновременно. Метод, который он использует внутри для синтаксического анализа, синхронизирован, поэтому, если у вас много потоков, вызывающих его одновременно, потоки блокируются.

Это должно быть зафиксировано в Java 8.

(см отчет об ошибке Java JI-9004591 - "Монитор раздора при вызове Double.parseDouble из нескольких потоков" - http://bugs.sun.com/view_bug.do?bug_id=7032154)

Я подозреваю, что это причина почему изменение в принятом ответе (перемещение Double.parseDouble) улучшило производительность.

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