Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java locking using "private final Lock" and synchronized result are not same

I try to write some code about Lock and synchronized and to compare their performance difference.

Code:

public abstract class Task {
    public abstract int getTotal();
}

// Lock test class
public class TaskWithLock extends Task implements Runnable {
    private static int total = 0;
    private final Lock lock = new ReentrantLock();

    public void run() {
         try {
            lock.lock();
            doSomething();
         } finally {
            lock.unlock();
         }
    }

    private void doSomething() {
        total++;
    }

    public int getTotal() {
        return total;
    }
}

// Synchronized test class
public class TaskWithSync extends Task implements Runnable {
    private static int total = 0;
    public void run() {
        synchronized ("") {
            doSomething();
        }
    }

    private void doSomething() {
        total++;
    }

    public int getTotal() {
        return total;
    }
}

// Test class
public class Test {
    public static void main(String[] args) throws Exception {
        int count = 100000;
        runTasks(TaskWithLock.class, count);
        runTasks(TaskWithSync.class, count);
    }

    public static void runTasks(Class<? extends Runnable> clazz, int count)
        throws Exception {
        List<Thread> list = new ArrayList<Thread>(count);
        for (int i = 0; i < count; i++) {
            list.add(new Thread(clazz.newInstance()));
         }

        for (int i = 0; i < count; i++) {
            list.get(i).start();
        }

        for (int i = 0; i < count; i++) {
            list.get(i).join();
        }

        System.out.println(clazz.getSimpleName() + "Total Result: "
            + ((Task) clazz.newInstance()).getTotal());
    }
}

My understand is the above Lock and synchronized code block should be the same effect, but the result I run them are not same, synchronized code is right, it is always 100000, but lock code is always incorrect, sometimes 99995,or 99997, or other result, but it is not 100000.

Console:

TaskWithLock Result: 99991

TaskWithSync Result: 100000

I think my code should have some error, or my understand about Lock is wrong, or Lock can not be used like this.

Please point out what could be wrong.

like image 717
Liu guanghua Avatar asked Feb 15 '23 10:02

Liu guanghua


1 Answers

In the lock-version, you are using one lock per instance. That means that every thread has its own lock, which ultimately renders the locks useless because no two threads use the same lock.

You need to change this to one central lock for all threads. Add static to this line:

private final Lock lock = new ReentrantLock();

so it becomes

private static final Lock lock = new ReentrantLock();
like image 58
Daniel S. Avatar answered Feb 17 '23 22:02

Daniel S.