一个对象锁使用常见问题

从一份代码讲起

首先看一份多线程代码,这份代码的执行结果是什么呢?

class Scratch {
    public static void main(String[] args) {
        Thing thing = new Thing();
        Thing thing2 = new Thing();
        Thread thread1 = new Thread(thing);
        Thread thread2 = new Thread(thing2);
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(thing.num);
    }

    static class Thing implements Runnable {
        private static int num = 0;

        @Override
        public synchronized void run() {
            for (int i = 0; i < 10000; i++) {
                num++;
            }
        }
    }
}

20000吗?并不是。正确答案是未知。。。明明貌似已经使用了synchronized关键字,为什么还会造成并发的问题呢?这就牵扯到了一个对象锁和表锁的问题。

对象锁和表锁的区别

java在对实例方法加锁的时候默认采用的是对象锁,所谓对象锁就是每个对象持有一把锁,多线程共同争用这个锁。但是上述的例子,我们声明了两个对象,导致拥有了两把锁,因此结果就会不符合预期的情况。

如何解决

解决这个问题,只需要使用类锁即可。下面给出了两种实现方式
第一种实现方式为使用synchronized 加类锁

    static class Thing implements Runnable {
        private static int num = 0;

        @Override
        public void run() {
            synchronized (Thread.class) {
                for (int i = 0; i < 10000; i++) {
                    num++;
                }
            }
        }
    }

第二种方式是使用synchronized修饰的静态方法

    static class Thing implements Runnable {
        private static int num = 0;

        @Override
        public void run() {
            add();
        }

        public synchronized static void add(){
            for (int i = 0; i < 10000; i++) {
                num++;
            }
        }
    }

经验证,上述两种方法均可以正确实现预期目标。

猜你喜欢

转载自blog.csdn.net/zhenlingcn/article/details/80284244