2015-08-09 4 views
1

Я изучаю java concurency.Почему мой многопоточный код приводит к зависанию?

Я пытаюсь оценить выполнение времени зависит от подсчета потоков (чтение и запись)

мой код:

public class Task5 { 
    public static int [] readerThreadCount = {1,10,100,1000}; 
    public static int [] writerThreadCount = {10, 1000, 1000000}; 


    public static void main(String[] args) throws InterruptedException { 
     for (int readCount : readerThreadCount) { 
      for (int writeCount : writerThreadCount) { 
       System.out.println(readCount + "/" + writeCount + " = " + test(readCount, writeCount, new ArrayHolderBySynchronized())); 
      } 
     } 

    } 

    private static long test(int readCount, int writeCount, ArrayHolder arrayHolder) throws InterruptedException { 
     CountDownLatch countDownLatch = new CountDownLatch(readCount + writeCount); 
     List<Thread> threads = new ArrayList<>(); 
     for (int i = 0; i < readCount; i++) { 
      threads.add(new Thread(new ArrayReader(arrayHolder, countDownLatch))); 
     } 
     for (int i = 0; i < writeCount; i++) { 
      threads.add(new Thread(new ArrayWriter(arrayHolder, countDownLatch))); 

     } 
     for(Thread thread:threads){ 
      thread.start(); 
     } 
     countDownLatch.await();//all threads started 
     long start = System.currentTimeMillis(); 
     for (Thread thread : threads) { 
      thread.join(); 
     } 
     return System.currentTimeMillis() - start; 

    } 
} 

class ArrayHolderBySynchronized extends ArrayHolder { 

    @Override 
    public synchronized int get(int index) { 
     return arr[index]; 
    } 

    @Override 
    public synchronized void write(int index, int value) { 
     arr[index] = value; 
    } 
} 

class ArrayReader implements Runnable { 
    ArrayHolder arrayHolder; 
    CountDownLatch countDownLatch; 

    ArrayReader(ArrayHolder arrayHolder, CountDownLatch countDownLatch) { 
     this.arrayHolder = arrayHolder; 
     this.countDownLatch = countDownLatch; 
    } 

    @Override 
    public void run() { 
     countDownLatch.countDown(); 
     arrayHolder.get(new Random().nextInt(ArrayHolder.ARRAY_SIZE)); 
    } 
} 

class ArrayWriter implements Runnable { 
    ArrayHolder arrayHolder; 
    CountDownLatch countDownLatch; 

    ArrayWriter(ArrayHolder arrayHolder, CountDownLatch countDownLatch) { 
     this.arrayHolder = arrayHolder; 
     this.countDownLatch = countDownLatch; 
    } 

    @Override 
    public void run() { 
     countDownLatch.countDown(); 
     arrayHolder.write(new Random().nextInt(ArrayHolder.ARRAY_SIZE), -1); 
    } 
} 

abstract class ArrayHolder { 
    public static int ARRAY_SIZE = 1_000_000; 
    protected int[] arr = generateArray(); 

    private int[] generateArray() { 
     int[] arr = new int[ARRAY_SIZE]; 
     for (int i = 0; i < ARRAY_SIZE; i++) { 
      arr[i] = i + 1; 
     } 
     return arr; 
    } 

    public abstract int get(int index); 

    public abstract void write(int index, int value); 
} 

выводит

1/10 = 0 
1/1000 = 1 

и зависаний.

У меня нет идей, почему.

помогите пожалуйста.

+2

У вас есть 1000000 ядер для этого. –

+0

Слишком большое число? – gstackoverflow

+2

Да. Нерест 1000000 потоков - это нонсенс. Обычно вы выбираете количество потоков, равное возможностям параллелизма вашего процессора, которые вы можете считать # ядрами, а затем балансируйте рабочую нагрузку между ними. Для четырехъядерного ядра -> 4 потока. –

ответ

1

Он не висит, начиная 1000000 темы, просто занимает в 1000 раз больше, чем начиная с 1000 нитей (пару минут, на моей машине):

> java Task5 

1/10 = 0 
1/1000 = 1 
1/1000000 = 63 
10/10 = 0 
10/1000 = 0 
10/1000000 = 60 
100/10 = 0 
100/1000 = 0 
100/1000000 = 63 
1000/10 = 0 
1000/1000 = 0 
1000/1000000 = 60 

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

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