2014-10-15 15 views
-1

Я пишу приложение, используя несколько потоков, чтобы подсчитать количество символов внутри txt-файла. Файл содержит 10 000 000 символов. 10 000 рядов и 1 000 колонн.Несколько потоков медленнее, чем один

EDITED
О первой части вопроса: Prevoius вопросов был о потоках, я использовал thread.join(); в неправильном направлении.

Вторая часть: Не могли бы вы помочь мне улучшить производительность и безопасность? Вот мой код (Использование Семафор требуется):

public class MultiThread implements Runnable { 

    HashMap<String, AtomicInteger> asciiMap = Maps.newHashMap(); 
    LinkedList<String> asciiLines = ReadDataFromFile.lines; 
    Semaphore mutex = new Semaphore(1); 
    AtomicInteger i = new AtomicInteger(0); 
    int index; 

    @Override 
    public void run() { 

     long actual = 0; 
     try { 
      Calculate calculate = new Calculate(); 
      long multiStart = System.currentTimeMillis(); 

      Thread first = new Thread(calculate); 
      Thread second = new Thread(calculate); 
      Thread third = new Thread(calculate); 

      first.start(); 
      second.start(); 
      third.start(); 

      first.join(); 
      second.join(); 
      third.join(); 

      long multiEnd = System.currentTimeMillis(); 
      actual = multiEnd - multiStart; 

     } catch (InterruptedException ex) { 
      Logger.getLogger(MultiThread.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     int sum = 0; 
     for (Map.Entry<String, AtomicInteger> entry : asciiMap.entrySet()) { 
      System.out.println("Char: " + entry.getKey() + " , number: " + entry.getValue()); 
      sum = sum + entry.getValue().get(); 
     } 

     System.out.println("Time: " + actual); 

    } 

    int increment() { 

     try { 
      mutex.acquire(); 
      index = i.incrementAndGet(); 
      mutex.release(); 

     } catch (InterruptedException ex) { 
      Logger.getLogger(MultiThread.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return index; 
    } 

    public class Calculate implements Runnable { 

     public Calculate() { 
     } 

     @Override 
     public void run() { 

      while (i.get() < asciiLines.size()) { 
       for (String oneCharacter : asciiLines.get(i.get()).split("")) { 
        if (asciiMap.containsKey(oneCharacter)) { 
         asciiMap.replace(oneCharacter, new AtomicInteger(asciiMap.get(oneCharacter).incrementAndGet())); 
        } else { 
         asciiMap.put(oneCharacter, new AtomicInteger(1)); 
        } 
       } 
       i = new AtomicInteger(increment()); 
      } 
     } 
    } 

} 

Каждый элемент внутри LinkedList содержит одну строку (1 000 символов).

+0

Почему бы вам не попробовать 1,2,4 нити. И вы уверены, что используете параллельные потоки? 'first.join()' выполняется до 'second.start()' – arunmoezhi

+0

Вы пробовали ['Fork/Join'] (http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html) подход? –

+0

Кроме того, ваша реализация hashmap выбрана неправильно - это не потокобезопасно, и ваше использование atominteger плохое. –

ответ

4

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

Thread first = new Thread(calculate); 
Thread third = new Thread(calculate); 
Thread second = new Thread(calculate); 

first.start(); 
second.start(); 
third.start(); 

first.join(); 
second.join(); 
third.join(); 
+0

какая глупая ошибка! – Serafins

+0

** Вот почему вы всегда должны использовать 'ExecutorService'! ** –

+0

уверен, это решение! Но безопасны ли потоки? – Serafins

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