Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Синхронизация потоков


Автор: batex 21.10.2011, 14:38
Возникла проблема с синхронизацией большого кол-во потоков с помощью функций wait(), notify(). Используется массив lock'ов. Код должен делать следующее: создает по параметру одинаковые потоки, которые уменьшают по очереди второй параметр. Потоки создаются, но в итоге программа виснет.
Код


public class NewThread
{
     
  public static int a;
  public static int b;
  public static Object[] sync;

    public static void main(String[] args) 
    {
     a = (Integer.parseInt(args[1]));
     b = (Integer.parseInt(args[0]));
     
     sync = new Object[b];
     for(int n = 0; n<b;n++)
         sync[n]=new Object();
     for(int i=0; i<b; i++)
        {
         if(i<b-1)
         {
             Thread t = new Thread(new WaitingThread(sync[i], sync[i+1]));
             t.start();
         }
         else
         {
             Thread t = new Thread(new WaitingThread(sync[i], sync[0]));
             t.start();
         }
             
           // System.out.println("1111");
            
        }
     
     synchronized(sync[0])
        {
           // System.out.println("Notify");
            sync[0].notify();         
     
        }
     
      
    }

    
    static class WaitingThread implements Runnable
    {

        static int nextId = 1;

        private Object sync;
        private int id;
        private Object sync1;
        
       
        public WaitingThread(Object sync,Object sync1) 
        {
            this.sync = sync;
            this.sync1 = sync1;
            id = nextId++;
        }

        public void run() 
        {        
         
            synchronized (sync) 
            {
             synchronized(sync1)
                {
                 sync1.notify(); 
             while(a > 0)
             {
                 
                   
                          
                    a--;
                    if (a < 0) break;
                    
                    System.out.println("Thread " +id +" "+ +a);
                    
                     
                      try 
                        {
                            sync.wait();
                        } catch (InterruptedException e) 
                        {
                         e.printStackTrace();
                        }
                    }
             } 
             
            }
            System.out.println("Threads " +id+ " finish");
        }
    }
}

Автор: LSD 21.10.2011, 15:56
Ctrl+Break выведет на консоль тред дамп, там можно посмотреть какой поток чем занят (только передай в конструктор Thread нормальное имя).

Ну и хотелось бы описание того, что ты пытался реализовать.

Автор: priam220 21.10.2011, 16:04
в определенный момент они все у тебя засыпают, следовательно:
Код

//                        try {
//                            sync.wait();
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }


Вывод:
Thread 1 9
Thread 3 8
Thread 3 6
Thread 3 5
Thread 3 4
Thread 3 3
Thread 3 2
Thread 3 1
Thread 3 0
Threads 3 finish
Thread 1 7
Threads 1 finish
Threads 2 finish
Threads 5 finish
Threads 7 finish
Threads 4 finish
Threads 9 finish
Threads 6 finish
Threads 8 finish
Threads 10 finish


P.S. не ясно, что вы пытаетесь сделать wait/notify, причем применяя их к разным переменным. Но если дело в декременте, то лучше сделать так:
Код

            public void run() 
            {        
             while(a > 0){
              synchronized(a)                                  
                 {  
                        if (a < 0) break;
                        a--;
                        System.out.println("Thread " +id +" "+ +a);                        
                 } 
              try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                 
                }
                System.out.println("Threads " +id+ " finish");
            }

Автор: batex 21.10.2011, 17:36
Цитата(LSD @ 21.10.2011,  15:56)
Ctrl+Break выведет на консоль тред дамп, там можно посмотреть какой поток чем занят (только передай в конструктор Thread нормальное имя).

Ну и хотелось бы описание того, что ты пытался реализовать.

Реализовать я хотел следующее: создать много одинаковых потоков, которые будут по очереди уменьшать параметр "а" на 1. У каждого потока есть свой sync для синхронизации.

Переменные для синхранизации разные - потому что я хотел сначала разбудить поток "n", потом уменьшить "а", потом разбудить следующий поток

Автор: priam220 21.10.2011, 21:13
Пришлось немного задержаться на работе, но в конце-концов я понял, что нужно. Вот рабочий код:
Код

package ex;
public class Major
{
      public static int a;
      public static int b;
      public static Object[] sync;

        public static void main(String[] args) throws InterruptedException 
        {
         a = 50;
         b = 10;
         
         sync = new Object[b];
         for(int n = 0; n<b;n++)
             sync[n]=new Object();
         for(int i=0; i<b; i++)
            {
             if(i<b-1)
             {
                 Thread t = new Thread(new WaitingThread(sync[i], sync[i+1]));
                 t.start();
                 Thread.sleep(100);
             }
             else
             {
                 Thread t = new Thread(new WaitingThread(sync[i], sync[0]));
                 t.start();
                 Thread.sleep(100);
             }
                 
               // System.out.println("1111");
                
            }     
          
        }

        
        static class WaitingThread implements Runnable
        {

            static int nextId = 1;

            private Object sync;
            private int id;
            private Object sync1;
            boolean flag = false;
           
            public WaitingThread(Object sync,Object sync1) 
            {
                this.sync = sync;
                this.sync1 = sync1;
                id = nextId++;
            }

        public void run() {
            synchronized (sync) {
                
                while (a > 0) {
                    synchronized (sync1) {
                        sync1.notify();

                        a--;
                        if (a < 0) {
                            break;
                        }
                        System.out.println("Thread " + id + " " + +a);

                    }
                    try {
                            sync.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                synchronized (sync1) {
                    sync1.notify();
                }
                
            }
            System.out.println("Threads " + id + " finish");
        }
    }
}


Код

Вывод:
Thread 1 49
Thread 2 48
Thread 3 47
Thread 4 46
Thread 5 45
Thread 6 44
Thread 7 43
Thread 8 42
Thread 9 41
Thread 10 40
Thread 1 39
Thread 2 38
Thread 3 37
Thread 4 36
Thread 5 35
Thread 6 34
Thread 7 33
Thread 8 32
Thread 9 31
Thread 10 30
Thread 1 29
Thread 2 28
Thread 3 27
Thread 4 26
Thread 5 25
Thread 6 24
Thread 7 23
Thread 8 22
Thread 9 21
Thread 10 20
Thread 1 19
Thread 2 18
Thread 3 17
Thread 4 16
Thread 5 15
Thread 6 14
Thread 7 13
Thread 8 12
Thread 9 11
Thread 10 10
Thread 1 9
Thread 2 8
Thread 3 7
Thread 4 6
Thread 5 5
Thread 6 4
Thread 7 3
Thread 8 2
Thread 9 1
Thread 10 0
Threads 2 finish
Threads 3 finish
Threads 1 finish
Threads 4 finish
Threads 5 finish
Threads 6 finish
Threads 7 finish
Threads 8 finish
Threads 9 finish
Threads 10 finish

Успехов!

Автор: batex 22.10.2011, 10:02
Большое спасибо за помощь!

Автор: LSD 24.10.2011, 10:28
Цитата(batex @  21.10.2011,  18:36 Найти цитируемый пост)
Реализовать я хотел следующее: создать много одинаковых потоков, которые будут по очереди уменьшать параметр "а" на 1. У каждого потока есть свой sync для синхронизации.

Переменные для синхранизации разные - потому что я хотел сначала разбудить поток "n", потом уменьшить "а", потом разбудить следующий поток 

Уменьшать счетчик можно и без синхронизации.

Автор: priam220 24.10.2011, 13:52
Цитата(LSD @  24.10.2011,  10:28 Найти цитируемый пост)
Уменьшать счетчик можно и без синхронизации.

Можно использовать AtomicInteger. Но чем он лучше блока синхронизации?.. smile 

Автор: LSD 24.10.2011, 14:12
Цитата(priam220 @  24.10.2011,  14:52 Найти цитируемый пост)
Можно использовать AtomicInteger. Но чем он лучше блока синхронизации?

Быстрее и прозрачнее логика.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)