我正在尝试在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
它会在每次运行时打印不同的数字。为什么是这样?我做错了什么?
答案 0 :(得分:1)
当您解锁以保证在
之前发生时,您不会创建内存屏障添加volatile boolean barr
并在解锁时将其写为真,并将锁中的时间更改为while (barr && flag[j] && 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
}
}
答案 1 :(得分:0)
我想,这是因为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]
将数组引用标记为volatile,而不是数组内容。
答案 2 :(得分:0)
正如其他人指出的那样,Java对数组元素没有易失性读/写。
您可以使用具有AtomicIntegerArray
和get()
的{{1}}带有易变的效果。
答案 3 :(得分:-2)
它不起作用,因为你使数组引用变为volatile,而不是内容(如已经指出的那样)。但是你总是可以在一个类中包含一个volatile字段并创建一个数组。