Не могу синхронизировать потоки в Java (используя семафоры) - PullRequest
0 голосов
/ 23 апреля 2011

Добрый день!

Я столкнулся с проблемой синхронизации потоков. Я пишу программу, которая похожа на ужин философов. У меня есть несколько процессов (3, например) и ресурсов (4, например). Каждый процесс может работать только с 2 бесплатными ресурсами. Это означает, что 1-й процесс может работать только с 1-м и 2-м ресурсами и т. Д.

Я решил использовать семафоры для моей цели. Проблема в том, что до сих пор нет синхронизации. Например, если 1-й и 3-й процессы работают с ресурсами, то 2-й процесс должен ждать, пока его ресурсы не будут освобождены. В моей программе иногда такое случается ... Иногда нет.

В чем проблема? Как я могу решить это?

Код здесь:

public class Sem
{
    public Sem()
    {
        available = new ConcurrentHashMap< Integer, Semaphore >();//Resources.

    for ( int i = 1; i <= 4; i++)
    {
        available.put( i, new Semaphore(1, true) );//Each resource contains semaphore.
    }
}

public void start( final int id )
{
    thisThread = new Thread()
    {
         public void run()
         {
            try
            {
                work( id );                                                 //Try to take resourses.
                Thread.currentThread().sleep(1000);
                release( id );                                              //Release resources.
            } catch (InterruptedException ex) {
                Logger.getLogger(Sem.class.getName()).log(Level.SEVERE, null, ex);
            }

         }
    };
    thisThread.start();
}

public synchronized void work( int id ) throws InterruptedException
{
    available.get(id).acquire();                                            //Try to take resourse[id] and resourse[id+1]
    available.get(id+1).acquire();                                          //Thread is blocking till it will be possible.

    System.out.printf("Acquired [%s], id = %d\n",Thread.currentThread().getName(), id);

}

public void release( int id )
{
    available.get(id).release();                                            //Release resources which hava been captured by thread.
    available.get(id+1).release();                                          //After this other thread can take these resourses.

    System.out.printf("Released [%s], id = %d\n",Thread.currentThread().getName(), id);
}


private ConcurrentHashMap< Integer, Semaphore > available;                  //Integer - id of thread[1..4]; Semaphore - is gate with param (1)
                                                                            //Available - map of resources which can be busy by processes.
Thread thisThread;
}

Я запускаю эту программу так:

Sem sem = new Sem();

        sem.start(1);
        sem.start(2);
        sem.start(3);

У меня есть несколько выходных сообщений, но мой любимый:

Acquired [Thread-1], id = 1
Acquired [Thread-3], id = 3
Released [Thread-1], id = 1
Acquired [Thread-2], id = 2
Released [Thread-3], id = 3
Released [Thread-2], id = 2 

Процесс 2 начал работать, а он не может этого сделать !!

Ответы [ 3 ]

3 голосов
/ 23 апреля 2011

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

1 голос
/ 23 апреля 2011

Исходя из вашего кода и выходных данных, возможно, что Поток 3 выпустил семафор 3, так что Поток 2, который его ожидал, заполучил его и распечатал сообщение до завершения потока 3.

Я заметил, что вы неметод синхронизированного освобождения.

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

synchronized(this) {
    available.get(id).acquire();                                            
    available.get(id+1).acquire();                                         
}

synchronized(this) {
   available.get(id).release();                                            
   available.get(id+1).release(); 
}
0 голосов
/ 27 ноября 2013

Сначала вы заканчиваете ресурс, а затем поток, поэтому сначала освободите семафор ресурса.Замените метод выпуска следующим:

public void release(int id) {
    resources.get(id + 1).release();
    resources.get(id).release();  
    //resources.get(id + 1).release();
    System.out.printf("Released [%s], id = %d\n", Thread.currentThread().getName(), id);
}
...