многопоточная производительность java для объекта синхронизации

#java #multithreading

#java #многопоточность

Вопрос:

Я пытаюсь протестировать производительность многопоточности с помощью объекта синхронизации. Однако, с 1 потоком или с 16 потоками время выполнения одинаково.

Остальная часть кода находится здесь. https://codeshare.io/5oJ6Ng

   public void run() {
        start = new Date().getTime();
        System.out.println(start);

            while (threadlist.size() < 9000) { //16 or more

                  //  try{Thread.sleep(100);}catch (Exception f){}

                Thread t = new Thread(new Runnable() {

                    public void run() {
                        while (add(1,3) < 1000000);
                        end = new Date().getTime();
                        System.out.println((end-start));
                    }
                });
                    threadlist.add(t);

               while( threadlist.iterator().hasNext()){
                   threadlist.iterator().next().start();
                   try{threadlist.iterator().next().join();}catch (Exception a){}
               }
            }

    }
 

Ответ №1:

Есть некоторые проблемы с вашим кодом. Первый:

 public void run() {
       while (true) {
            add(1, 3);
        }
 }
 

Эти потоки никогда не перестают работать, я бы предложил переписать вашу логику на:

    public void (run) {
        while(add(1,3) < 1000000);
        System.out.println("now 1000000");
   }

   public int add(int val1, int val2) {
        synchronized (this) {
            this.sum1  = val1;
            this.sum2  = val2;
            return this.sum1   this.sum2;
            }
        }
    }
 

Вы запускаете потоки, но никогда не вызываете join , в конечном итоге вам нужно будет это сделать.

Вы создаете только 1 поток вместо 16, которые вы хотели:

 if (threadlist.size() < 1)
 

вы хотите

 if (threadlist.size()  < 16)
 

Наконец, не ожидайте увеличения производительности с помощью этого кода, поскольку вы синхронизируете объект:

 synchronized (this){...}
 

Таким образом, в основном ваш add метод выполняется последовательно, а не параллельно, поскольку потоки будут ожидать synchronized (this) и вызывать run on только во время внутри вашего блока кода, обернутого оператором synchronized .

Попробуйте измерить свое время, добавив start = new Date().getTime(); перед параллельной областью и end = new Date().getTime(); после.

Вы можете просто использовать свой код для:

 public void run() {
    start = new Date().getTime();
    System.out.println(start);
    while (threadlist.size() < 16) {
         Thread t = new Thread(() -> {
              while (add(1,3) < 1);
              System.out.println("now 1000000");
        });
        threadlist.add(t);
    }
    threadlist.forEach(Thread::start);
    
    threadlist.forEach(thr-> {
            try { thr.join();} 
            catch (InterruptedException e) { e.printStackTrace();}
     });
     end = new Date().getTime();
     System.out.println("Time taken : " (end-start));

     public int add(int val1, int val2) {
            synchronized (this) {
                this.sum1  = val1;
                this.sum2  = val2;
                return this.sum1   this.sum2;
                }
          }
      }
 

Ответ №2:

Вы значительно обновили свой код с тех пор, как ответил @dreamcrash.

В текущей версии есть следующие проблемы:

 while( threadlist.iterator().hasNext()) {
   threadlist.iterator().next().start();
   try{threadlist.iterator().next().join();}catch (Exception a){}
 }
 

Это запускает поток, а затем сразу же будет сидеть сложа руки, пока этот поток полностью не выполнит свою работу, а затем запустит другой поток. Следовательно, вы никогда не используете более 1 активного потока одновременно.

catch (Exception a){}

Вы изучаете / отлаживаете, и вы это делаете? О боже. Не делайте этого. Никогда не пишите блок catch подобным образом. Обновите свою IDE или мышечную память: правильный код «я не хочу думать об исключениях прямо сейчас» catch (Exception a) { throw new RuntimeException("Unhandled", a);} . Чтобы было ясно, это не проблема, но это такая плохая привычка, ее нужно было вызвать.

synchronized (this) {

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

В более общем случае вычисления, которые вы пытаетесь ускорить, связаны с аккумулятором.

аккумулятор — это другое слово, обозначающее «распараллеливание здесь совершенно невозможно, это безнадежно».

Алгоритм не может включать аккумуляторы, если вы хотите его распараллелить, что и делает многопоточность (по крайней мере, если целью нескольких потоков является ускорение процесса). Этот алгоритм не может быть ускорен потоками. точка.

Обычно алгоритмы можно переписать, чтобы перестать полагаться на аккумуляторы. Но это явно упражнение, чтобы увидеть эффект, так что просто найдите что-нибудь еще, на самом деле. Не блокируйте один объект для всего вычисления: только один поток действительно выполняет работу, все остальные 999 просто ждут.