【问题标题】:Implement Peterson Lock in Java在 Java 中实现彼得森锁
【发布时间】:2011-08-23 21:06:26
【问题描述】:

我正在尝试在 Java 中实现 Peterson's algorithm,并暂时创建了以下内容

public class Peterson {
    private volatile boolean[] flag = new boolean[2];
    private volatile int victim;

    public void lock(int id)
    {
        //System.out.println(id);
        int i = id;
        int j = 1 - id; 
        flag[i] = true;
        victim = i;
        while (flag[j] && victim == i) {};
    }

    public void unlock(int id)
    {
        flag[id] = false;
    }
}

我得到以下代码来测试锁...

class Counter {
    private int value;

    public Counter(int c)   {
        value = c;
    }

    public int get()
    {
        return value;
    }

    public int getAndIncrement()    {       
        return value++;
    }
}


class Thread1 implements Runnable   {
    private Counter c;
    private int id;
    private List<Integer> values;
    private Peterson lock;

    public Thread1(Counter c, int id, List<Integer> values, Peterson l) {
        this.c = c;
        this.id = id;
        this.values = values;
        this.lock = l;
    }

    public void run() {

        while (true)
        {
            lock.lock(id);
            try {
                try {

                    if (c.get() > 20000)
                        return;

                    int n = c.getAndIncrement();
                    values.add(n);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            finally {
                lock.unlock(id);
            }
        }
    }
}

public class Tmp    {

    public static void main(String[] args) throws IOException   {

        Counter  c = new Counter(1);
        Thread[] t = new Thread[2];
        List<Integer> values = new ArrayList<Integer>();
        Peterson l =  new Peterson();

        for (int i = 0; i < t.length; ++i)  {
            t[i] = new Thread(new Thread1(c, i, values, l));
            t[i].start();
        }

        System.out.println(values.size());
    }
}

虽然我希望 System.out.println(values.size()); 打印 20000 它在每次运行时打印不同的数字。为什么是这样?我做错了什么?

【问题讨论】:

    标签: java concurrency locking


    【解决方案1】:

    解锁时不会创建内存屏障以保证发生之前

    添加一个volatile boolean barr并在unlock中写入true并将lock中的while更改为while (barr &amp;&amp; flag[j] &amp;&amp; victim == i) {};

    这样你就不用等待你创建的线程了

    for (int i = 0; i < t.length; ++i)  {
        t[i] = new Thread(new Thread1(c, i, values, l));
        t[i].start();
    }
    
    for (int i = 0; i < t.length; ++i)  {
        try{
            t[i].join();
        }catch(InterruptedException e){
            Thread.currentThread().interrupt();//don't expect it but good practice to handle anyway
        }
    }
    

    【讨论】:

    • 我不明白你对barr 的意思,我应该在unlock 中设置barr = true,在lock 方法中怎么样?
    • @mario 您希望解锁之前的操作发生在成功锁定之后的操作,因此您只需要读取锁定中的barr发生在之前,volatiles 只保证在同一个字段上)
    【解决方案2】:

    我猜,这是因为 Lock 类中的 lock() 方法不是原子的。具体来说,这段代码修改了 两个 内存地址,然后使用它们都没有锁定来检查条件:

    public void lock(int id)
    {
        ...
        flag[i] = true;
        victim = i;
        while (flag[j] && victim == i) {};
    }
    

    如果两个线程在执行时交错,算法会起作用

        flag[i] = true;
        victim = i;
    

    其次,因为private volatile boolean[] flag = new boolean[2] 将数组引用标记为易失性,而不是数组内容。

    【讨论】:

    • 我没看懂你的第一句话,你的意思是Lock类中的“锁”不是原子的?关于第二种,有没有办法将数组元素标记为volatile?
    • 对于volatile 2-booleans 数组,用具有 4 个可能值的 volatile int 替换它怎么样?
    • @victor 这不是真的可以接受,因为如果线程 0 将位 0 ​​设置为真,而线程 1 使用 flag = flag|1&lt;&lt;id; 将位 1 设置为真会怎样(这就像增量的标准问题:load->alter ->store) 01、10(都不正确)或 11(正确)你需要一个原子比较和交换来用 int 解决这个问题
    【解决方案3】:

    正如其他人指出的那样,Java 对数组元素没有易失性读/写。

    您可以使用AtomicIntegerArray,它具有get()set() 的不稳定效果。

    【讨论】:

      【解决方案4】:

      它不起作用,因为您使数组引用 volatile ,而不是内容(正如已经指出的那样)。但是你总是可以在一个类中包装一个 volatile 字段,然后创建一个数组。

      【讨论】:

        猜你喜欢
        • 2012-07-20
        • 1970-01-01
        • 2013-09-02
        • 2017-05-05
        • 2011-02-24
        • 1970-01-01
        • 1970-01-01
        • 2015-10-19
        • 1970-01-01
        相关资源
        最近更新 更多