判断锁是否生效

判断一个锁的作用时,首先看锁的对象是什么?也即是synchronized锁定了谁的 Monitor 计数器
是类本身(例如静态变量或者静态方法,或者直接对类名.class进行上锁),还是成员变量/方法
再看上锁的方法是否运行在同一个实例之上
如果是对类本身上锁,那么无论是一个实例还是多个实例都是有效的,因为上锁的对象全局唯一
如果是对类的成员变量/方法上锁:
运行在同一个实例对象上,那么这个锁就可以生效
运行在不同的实例对象上,那么这个锁就无效

结合具体代码来看

实例1:

首先add()是一个成员函数,那么synchronized上锁的就是当前的实例对象,而t1和t2的实例对象都是lock,那么它们调用add()时使用的都是同一个的成员变量count
此时synchronized是生效的
也即是说,如果此时不对add()函数上锁,那么count++操作的原子性就得不到保证,也即是

  1. count从主内存中取出
  2. count+1
  3. count放回主内存
    这三步并不能保证被一起执行,那么就可能出现t1和t2同时取出count加1后再放回去。
    例如:count=1时,t1和t2同时调用add()函数进行操作。t1加1后count等于2,t2加1后count也等于2,所以导致最后答案比预期结果小
package;
public class 锁是否生效 {
    int count;
    // 定义一个同步方法,确保线程安全
    synchronized void add() {
        count++;
    }

    public static void main(String[] args) {
        锁是否生效 lock = new 锁是否生效();

        // 创建线程t1,并重写其run方法
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100000000; i++) {
                    lock.add();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000000000; i++) {
                    lock.add();
                }
            }
        });

        // 启动线程t1
        t1.start();
        t2.start();
        // 等待t1执行完毕,可以在这里加入try-catch来处理可能的中断异常
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印最终的count值
        System.out.println("最终的count值为: " + lock.count);
    }
}

实例2

add()依然是一个成员函数,synchronized上锁的是当前的实例对象
但是注意,t1和t2此时的实例对象并不相同,它们调用add()时使用的并不是同一个的成员变量count,t1使用的是lock1.count,t2是lock2.count
所以synchronized是不生效的
也即是说,如果此时不对add()函数上锁,也是不会发生错误的

package;

public class 锁是否生效 {
    int count;

    // 定义一个同步方法,确保线程安全
    synchronized void add() {
        count++;
    }

    public static void main(String[] args) {
        // 创建线程t1,并重写其run方法
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                锁是否生效 lock1 = new 锁是否生效();
                for (int i = 0; i < 10000; i++) {
                    lock.add();
                }
                System.out.println("最终的count值为: " + lock.count);

            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                锁是否生效 lock2 = new 锁是否生效();
                for (int i = 0; i < 10000; i++) {
                    lock.add();
                }        
                System.out.println("最终的count值为: " + lock.count);

            }
        });

        // 启动线程t1
        t1.start();
        t2.start();
        // 等待t1执行完毕,可以在这里加入try-catch来处理可能的中断异常
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打印最终的count值
    }
}

实例3

如果此时将count设置为静态变量,那么最后输出的值就会发生错误,因为就算有t1和t2使用的是两个实例对象,但t1和t2的add()函数中使用的是同一个count
静态变量具有全局可见性,所以是唯一的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值