首页 > 解决方案 > java线程同步和锁定没有效果?

问题描述

非常困惑为什么我在同步或锁定方法中执行“i++”时会得到随机结果?

public class aaa implements Runnable {
    static int count = 0;
    public static void main(String[] args) {
        aaa aaa = new aaa();
        aaa.create();
    }
    public void create() {
        ExecutorService executor = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 1000; i++) {
            aaa thread = new aaa();
            executor.execute(thread);
        }
        executor.shutdown();
        while (true){
            if(executor.isTerminated()){
                System.out.println("a " + count);
           break;
            }
        }
    }
    @Override
    public void run() {
        this.test();
    }
    public void test() {
        Lock lock = new ReentrantLock();
        try {
            lock.lock();
            count++;
            System.out.println(count);
        } finally {
            lock.unlock();
        }
    }
}

或者:

    public  synchronized void test() {
            count++;
            System.out.println(count);
        }

结果是一个随机数,有时是 1000,有时是 998、999 ...等等,并且“测试”方法内部的打印不是按顺序排列的,就像:

867
836
825
824
821
820
819
817
816
a 999

但是,如果它在同步块中,一切看起来都很好:

    public void test() {
        synchronized (aaa.class) {
            count++;
            System.out.println(count);
        }
    }

结果:

993
994
995
996
997
998
999
1000
a 1000

我认为上面所有的方法都应该给我相同的结果1000,并且自增应该是顺序的,但只有最后一种方法有效。代码有什么问题?请帮忙!!!

标签: javamultithreadingconcurrencythreadpoolsynchronized

解决方案


您正在创建 aaa 的多个实例,每个实例都会创建自己的 ReentrantLock,并且每个执行中的线程都会顺利地从自己的实例中获取锁。

public void test() {
        Lock lock = new ReentrantLock();
        try {
            lock.lock();
            count++;
            System.out.println(count);
        } finally {
            lock.unlock();
        }
    }

由于 aaa 有多个实例,每个线程都在自己的实例上运行,同步方法使用 aaa.class 的当前对象

public  synchronized void test() {
        count++;
        System.out.println(count);
    }

在这种方法中获得正确结果的原因是,您使用 aaa.class 作为同步对象

public void test() {
    synchronized (aaa.class) {
        count++;
        System.out.println(count);
    }
}

解决方案是,在所有线程中重用相同的锁(ReentrantLock)。将锁定义在与变量计数相同的级别将解决该问题。


推荐阅读