Peterson算法逻辑出了什么问题?

时间:2017-08-03 12:11:18

标签: java multithreading algorithm locking

我是多线程编程的新手。在我的代码中,线程试图获取几行的锁。对于少数上下文切换,这些行工作得非常好,但随后停止(可能是死锁)。

另一方面,如果使用synchronized块,那么一切正常。

我有四节课。

1。 PetersonAlgorithm.java

package com.ashish.master;

public class PetersonAlgorithm {

    boolean wantCS[] = {false, false};
    int turn = 1;

    public void requestCS(int i) {
        System.out.println("Lock requested by the thread - " + i);
        wantCS[i] = true;
        turn = 1 - i;
        while(wantCS[1-i] && turn == 1-i);

    }

    public void releaseCS (int i) {
        wantCS[i] = false;
        turn = i - 1;
        System.out.println("Lock released by the thread - " + i);
    }

}

如果有人认为上述算法不正确,请告诉我,并随时提出建议。

2。 Runner.java

package com.ashish.master;

public class Runner {

    public static Incrementer runnableInstance = new Incrementer();
    public static Thread inc1 = new Thread(runnableInstance, "0");
    public static Thread inc2 = new Thread(runnableInstance, "1");

    public static void main(String args[]) {

        inc1.start();
        inc2.start();

        try{
            inc1.join();
            inc2.join();
        } catch (InterruptedException ex) {
            System.out.println("The threads have been interrupted while waiting for the join ---> " + ex.getMessage());
        }

        System.out.println("The total turns taken by incrementer are ----> " + runnableInstance.turns);

    }

}

第3。 Incrementer.java - 如果使用synchronized块而不是Peterson算法,一切正常。

package com.ashish.master;

public class Incrementer implements Runnable {

    public long turns = 0;
    public PetersonAlgorithm pa = new PetersonAlgorithm();

    @Override
    public void run() {

        System.out.println("Thread " + this.toString() + "started.....");
        while(true) {
            pa.requestCS(Integer.parseInt(this.toString()));
//          synchronized(this) {
                if(DataStore.data < 1000000) printCriticalSection();
                else break;
//          }
            pa.releaseCS(Integer.parseInt(this.toString()));
        }

    }

    public void printCriticalSection() {
        System.out.println("The value of the number is increased by thread " +
                this.toString() +" to --> " + DataStore.increase());
            turns ++;       
    }

    @Override
    public String toString() {
        return Thread.currentThread().getName();
    }

}

4。 DataStore.java 用于模拟数据源的类 - 只需增加数量

package com.ashish.master;

public class DataStore {

    public static long data = 0L;

    public static long increase() {
        DataStore.data += 1;
        return DataStore.data;
    }

}

2 个答案:

答案 0 :(得分:1)

你的runnables从不观察彼此的监视器(wantCS和转弯),因为它们有不同的实例......每个runnable都需要使用同一组共享的监视器!

使用蓝色药丸并使用同步块访问使您的PetersonAlgorithm变量静态不变...

或者拿红色药丸为你的旗帜监视器(wantCS)和指示器监视器(转向)创建一个Class。然后用一个“自己的旗帜”,一个“观察旗”和一个“指示符”来定义你的runnable。两个Runnable都将具有相同的指示符实例(因此需要同步),而标志实例将被越过(R1的自己的标志将是R2的观察标志,R2的自己的标志是R1的观察标志)。您也应该同步标记方法,因为您不希望在观察时升高或降低标记。

然后几步:

  1. Runnables举起他们的旗帜
  2. Runnables转动共享指标(设置为对手runnable的id)
  3. 等待对手的旗帜升起并且指示器设置为对手。
  4. 非等待的对手做了它的东西,然后降低它的旗帜。
  5. 等待的对手停止等待(对手的旗帜降低了),做了其中的东西并降低了旗帜。

答案 1 :(得分:0)

每个可运行的实例都有自己的PetersonAlgorithm实例。因此,两个runnables对彼此一无所知,并且总是能够立即访问临界区。尝试使用static方法将PetersonAlgorithm类实现为static类。然后改变行

pa.requestCS(Integer.parseInt(this.toString()));
// ...
pa.releaseCS(Integer.parseInt(this.toString()));

进入

PetersonAlgorithm.requestCS(Integer.parseInt(this.toString()));
// ...
PetersonAlgorithm.releaseCS(Integer.parseInt(this.toString()));