可重入锁无法正确更新共享资源

use*_*362 1 java concurrency multithreading

我有一个共享变量计数,我在方法中递增它increment(),并且两个线程正在访问它。我得到了错误的最终计数。这是代码片段:

public class ReentrantLockTest {
    static volatile int count = 0;

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

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 10000; i++){
                    increment();
                }
            }
        });


        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 10000; i++){
                    increment();
                }
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();
        System.out.println("Counter variable : "+count);

    }
    private static void increment(){
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            count++;
        }finally {
           lock.unlock();
        }


    }
}
Run Code Online (Sandbox Code Playgroud)

计数器变量为 19957/19678..ect。它应该是 20000。如果我正在使用synchronized,那么我将得到 20000。请帮助我。

Sla*_*law 5

ReentrantLock每次increment()调用时您都会创建一个新的。为了正确保护状态,每当访问该特定状态时,您都需要同步/锁定同一对象。您需要更改代码,以便每次都使用相同的锁实例。

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest {

  private static final ReentrantLock LOCK = new ReentrantLock();
  private static int count;

  public static void increment() {
    LOCK.lock();
    try {
      count++;
    } finally {
      LOCK.unlock();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    Runnable action = () -> {
      for (int i = 0; i < 10_000; i++) {
        increment();
      }
    };

    Thread t1 = new Thread(action);
    Thread t2 = new Thread(action);
 
    t1.start();
    t2.start();

    t1.join();
    t2.join();
    System.out.println("Counter variable : " + count);
  }
}
Run Code Online (Sandbox Code Playgroud)

另外,请注意,由于count是由锁保护的,并且因为在读取 的值并将其打印出来之前调用 和 ,所以实际上没有必要t1.join()出现这种情况。t2.join()countcountvolatile