使用ReentrantLock的Java中的竞争条件

使用ReentrantLock的Java中的竞争条件,java,concurrency,locking,Java,Concurrency,Locking,在下面的代码中,ReentrantLock用于防止next()方法生成奇数。但是next()方法生成奇数。但如果我把它改成nextWithTry,它不会生成奇数。有人能解释一下原因吗 class Generator{ Lock l = new ReentrantLock(); volatile int c = 0; public int next(){ l.lock(); c++; c++; l.unlock();

在下面的代码中,ReentrantLock用于防止next()方法生成奇数。但是next()方法生成奇数。但如果我把它改成nextWithTry,它不会生成奇数。有人能解释一下原因吗

class Generator{

    Lock l = new ReentrantLock();
    volatile int c = 0;

    public int next(){

        l.lock();
        c++; c++;
        l.unlock();

        return c;
    }

    public int nextWithTry(){//This method works fine...

        try{
            l.lock();
            c++; c++;
            return c;
        }finally{   
            l.unlock();
        }
    }
}

class W implements Runnable{

    private Generator r;

    public W(Generator r){
        this.r = r;
    }

    @Override
    public void run() {

        int x;

        while(true){
            if(((x = r.next()) % 2) != 0){
                System.out.println(x + " odd number Found");
                break;
            }
        }
    }
}

public class Testing {

    public static void main(String[] args) {

        Generator r = new Generator();

        W w1 = new W(r);

        new Thread(w1).start();
        new Thread(w1).start();
    }
}

如果在
unlock
return
之间增加了
c
,会发生什么情况

public int next(){
    //lock, exclusive access
    l.lock();
    //increment, all good
    c++; c++;
    //unlock, another thread can access
    l.unlock();

    //any number of other threads call `next` and can acquire the lock

    //return some random value
    return c;
}
当您最后使用
,只有待返回的
c
值已经在堆栈上时才会释放

public int nextWithTry() {
    try {
        //lock, exclusive access
        l.lock();
        //increment, all good
        c++; c++;
        //place the value of `c` to be returned on the stack (java passes by value)
        return c;
    } finally {   
        //unlock _after_ the return has been copied
        l.unlock();
    }
}
事实上,直接推荐使用
try..finally

在大多数情况下,应使用以下习语:

 Lock l = ...;
 l.lock();
 try {
     // access the resource protected by this lock
 } finally {
     l.unlock();
 }

这是为了避免类似这样的问题以及更严重的问题,即
异常
会导致
无法解锁。

我正在使用java版本1.7.051和eclipse JUNO。我试着不使用挥发油。“同样的事情也会发生。”我相信你的答案是正确的。有一个排序问题,但它不是在jit的优化中,而是在您指出的代码本身。或者您可以在解锁之前将
c
的值存储在局部变量中,然后返回该值,如果您想避免
由于某种原因而尝试
阻塞。@stvcisco是的,当然可以。但建议使用
try…finally
以避免锁未释放的问题。@maamapun?