使用ReentrantLock在Java中的竞争条件

时间:2015-04-20 18:40:41

标签: java concurrency locking

在下面的代码中,ReentrantLock用于防止next()方法生成奇数。但next()方法生成奇数。但是,如果我将其更改为nextWith尝试它不会产生奇数。任何人都可以解释这个原因吗?

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();
    }
}

1 个答案:

答案 0 :(得分:3)

cunlock之间的其他内容增加return时会发生什么?

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;
}

当您使用finally时,只有在要返回的lock的值已经在堆栈中时才会释放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();
    }
}

事实上,the documentation直接建议使用try..finally

  

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

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

这是为了避免像Exception导致Lock无法解锁的问题以及更严重的问题。