Java中无法同步线程(使用信号量)

发布于 2024-11-02 17:46:53 字数 2611 浏览 5 评论 0原文

再会!

我遇到了同步线程的问题。我正在编写类似于哲学家晚餐的程序。我的进程(例如 3 个)和资源(例如 4 个)很少。每个进程只能使用 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开始工作,而他却做不到!

Good day!

I have met problem with synchronizing threads. I am writing program which is like dinner philosophers. I have few processes (3 for example) and resources (4 for example). Each process can work only with 2 free resources. That means that 1st process can work only with 1st and 2nd resources and etc.

I decided to use semaphores for my aim. Problem is that is still doesn't have synchronization. For example if 1st and 3rd processes are working with resources then 2nd process must wait until his resources will not be release. In my program sometimes it happens... Sometimes it doesn't.

What is the problem? How can i solve that?

Code is here:

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;
}

I start this program like this:

Sem sem = new Sem();

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

I have few output messages but my favorite:

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 

Process 2 started worked while he can't do it!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不知在何时 2024-11-09 17:46:53

我认为你应该以与获取锁相反的顺序释放锁。

I think you should release the locks in reverse order in which they were obtained.

初懵 2024-11-09 17:46:53

根据您的代码和输出,线程 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(); 
}

Based on your code and output, it is possible that Thread 3 released semaphore 3 so Thread 2 that was waiting for it - acquired it and printed the message before Thread 3 completed.

I noticed that you didn't synchronized release method.

I highly recommend putting synchronized block around both acquire and release.

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

synchronized(this) {
   available.get(id).release();                                            
   available.get(id+1).release(); 
}
梦在深巷 2024-11-09 17:46:53

您先完成资源,然后再完成线程,因此首先释放资源信号量。将释放方法替换为以下内容:

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);
}

You are finishing with the resource first then the thread so release the resource semaphore first. Replace the release method with followings:

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文