与信号量同步的“阶段”序列无法正常工作

我正在学习线程和同步,我正在尝试建立一个“阶段”系统,其中第一阶段生成一条消息(为方便起见,一个 int),然后将其传递给第二阶段,第二阶段修改它(乘以2),然后将其传递到最后一个阶段,该阶段进一步修改它并将其打印到控制台。问题是第三阶段永远不会运行,即使它收到了消息。

在我的示例中,我设置了一个名为“资源”的信号量数组,其中信号量 A(索引 0)有 4 个许可,信号量 B 有 3 个,C 有 2 个。所有设置都是公平的。

我尝试将信号量设置为公平,但这并没有解决我的问题。我也试过改变睡眠时间,但没有成功。

class Fase1 extends Thread{

    private int i = 0;

    private Semaphore[] resources;

    private Fase2 recipient;


    public Fase1(Semaphore[] res, Fase2 fase2){

        recipient=fase2;

        resources=res;

    }


    @Override

    public void run(){

        try{

            while(true){

                resources[0].acquire(2);

                resources[1].acquire(2);

                recipient.receiveMessage(i);

                i++;

                sleep(200);

                resources[1].release(2);

                resources[0].release(2);

            }

        } catch (InterruptedException e){

        }

    }

}


class Fase2 extends Thread{

    private Semaphore[] resources;

    private Fase3 recipient;

    private boolean receivedMessage = false;

    private int message = 0;


    public Fase2(Semaphore[] res, Fase3 fase3){

        recipient=fase3;

        resources=res;

    }


    @Override

    public void run(){

        try{

            while(true){

                if(receivedMessage){

                    resources[0].acquire(2);

                    resources[1].acquire(2);

                    resources[2].acquire(2);

                    recipient.receiveMessage(message*2);

                    receivedMessage = false;

                    sleep(200);

                    resources[2].release(2);

                    resources[1].release(2);

                    resources[0].release(2);

                }

            }

        } catch (InterruptedException e){

        }

    }

    public void receiveMessage(int msg){

        message = msg;

        receivedMessage = true;

    }

}


我注意到许可证不知何故被搞砸了,几乎就像一些线程没有正确释放它们一样,即使这对我来说似乎是正确的。


开心每一天1111
浏览 64回答 1
1回答

神不在的星期二

您的设计存在一个根本缺陷:您正在同步对message资源的访问,而不是对receivedMessage标志的访问。当您在线程 #2 中设置标志时true,JVM 没有义务将该写入传播到线程 #3,因为该线程在进入块内之前不会执行同步if,而这很可能永远不会发生。这同样适用于线程#1 和#2 之间的通信。and操作充当同步点,并且将使写入在线程间可见,因此您需要在检查标志之前调用它们acquire()。例如在:release()Fase3  @Override    public void run(){        try{            while(true){                resources[1].acquire(2); // All writes by thread #2 are now visible                if(receivedMessage){                    resources[2].acquire(2);                    System.out.println(message+1);                    sleep(200);                    receivedMessage = false;                    resources[2].release(2);                }                resources[1].release(2);            }        } catch (InterruptedException e){        }    }还有另一种解决方案,即制作receivedMessageflags volatile,但正确使用单个锁定机制更清晰。作为旁注,最好使用Runnables 而不是 extendingThread。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java